API Reference
Complete REST API documentation for programmatic access to Ebla. All endpoints use JSON for request and response bodies.
Overview
The Ebla API is organized around REST principles. It accepts JSON-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes and verbs.
Base URL
https://your-server:6333/api/v1
Content Type
All requests must include the Content-Type header:
Content-Type: application/json
API Versioning
The API version is included in the URL path. The current version is v1. When breaking changes are introduced, a new version will be released while maintaining backwards compatibility for existing versions.
Authentication
Most API endpoints require authentication. Ebla uses JWT (JSON Web Tokens) for authentication.
Obtaining a Token
Authenticate with your email and password to receive access and refresh tokens:
POST /api/v1/auth/login
Content-Type: application/json
{
"email": "user@example.com",
"password": "your-password"
}
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
"expires_in": 3600,
"token_type": "Bearer"
}
Using the Token
Include the access token in the Authorization header for all authenticated requests:
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Token Refresh
Access tokens expire after 1 hour. Use the refresh token to obtain a new access token without re-authenticating:
POST /api/v1/auth/refresh
Content-Type: application/json
{
"refresh_token": "eyJhbGciOiJIUzI1NiIs..."
}
API Keys
For server-to-server integrations, you can create long-lived API keys:
POST /api/v1/user/api-keys
Authorization: Bearer <token>
{
"name": "CI/CD Integration",
"scopes": ["library:read", "library:write", "sync:push"]
}
Use API keys with the X-API-Key header:
X-API-Key: ebla_key_abc123...
Error Handling
The API uses standard HTTP status codes to indicate success or failure:
| Status | Meaning |
|---|---|
200 |
Success |
201 |
Created - resource successfully created |
204 |
No Content - success with no response body |
400 |
Bad Request - invalid parameters |
401 |
Unauthorized - missing or invalid token |
403 |
Forbidden - insufficient permissions |
404 |
Not Found - resource doesn't exist |
409 |
Conflict - resource already exists or conflict detected |
422 |
Unprocessable Entity - validation failed |
429 |
Too Many Requests - rate limit exceeded |
500 |
Internal Server Error |
Error Response Format
All errors return a consistent JSON structure:
{
"error": {
"code": "validation_failed",
"message": "The request body contains invalid fields",
"details": [
{
"field": "email",
"message": "must be a valid email address"
}
]
}
}
Common Error Codes
| Code | Description |
|---|---|
invalid_token |
The access token is invalid or expired |
permission_denied |
User lacks required permissions |
not_found |
The requested resource was not found |
validation_failed |
Request validation failed |
conflict |
A sync conflict was detected |
rate_limited |
Too many requests, slow down |
quota_exceeded |
Storage or usage quota exceeded |
Pagination
List endpoints support cursor-based pagination for efficient traversal of large datasets.
Request Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
integer | 50 | Number of items to return (max 100) |
cursor |
string | - | Cursor for next page (from previous response) |
order |
string | desc | Sort order: asc or desc |
Response Format
{
"data": [...],
"pagination": {
"cursor": "eyJpZCI6IjEyMzQ1In0=",
"has_more": true,
"total": 1523
}
}
Example: Paginating Through Results
# First page
GET /api/v1/libraries/abc123/files?limit=50
# Next page (use cursor from previous response)
GET /api/v1/libraries/abc123/files?limit=50&cursor=eyJpZCI6IjEyMzQ1In0=
Auth Endpoints
POST /auth/login
Authenticate a user and receive tokens.
POST /api/v1/auth/login
{
"email": "user@example.com",
"password": "your-password"
}
Response 200:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
"expires_in": 3600,
"token_type": "Bearer",
"user": {
"id": "usr_abc123",
"email": "user@example.com",
"name": "John Doe",
"is_admin": false
}
}
POST /auth/refresh
Refresh an access token using a refresh token.
POST /api/v1/auth/refresh
{
"refresh_token": "eyJhbGciOiJIUzI1NiIs..."
}
Response 200:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"expires_in": 3600,
"token_type": "Bearer"
}
POST /auth/logout
Invalidate tokens and end the session.
POST /api/v1/auth/logout
Authorization: Bearer <token>
Response 204: No Content
POST /auth/cli/initiate
Initiate browser-based CLI authentication. Returns a device code for the user to enter in the browser.
POST /api/v1/auth/cli/initiate
Response 200:
{
"device_code": "abc123def456",
"user_code": "ABCD-EFGH",
"verification_url": "https://server:6333/app/cli-auth",
"expires_in": 300,
"poll_interval": 5
}
POST /auth/cli/poll
Poll for CLI authentication completion.
POST /api/v1/auth/cli/poll
{
"device_code": "abc123def456"
}
Response 200 (pending):
{
"status": "pending"
}
Response 200 (authorized):
{
"status": "authorized",
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
"expires_in": 3600,
"user": { ... }
}
User Endpoints
GET /user/me
Get the authenticated user's profile.
GET /api/v1/user/me
Authorization: Bearer <token>
Response 200:
{
"id": "usr_abc123",
"email": "user@example.com",
"name": "John Doe",
"is_admin": false,
"created_at": "2026-01-01T00:00:00Z",
"storage_used": 1073741824,
"storage_quota": 10737418240
}
PATCH /user/me
Update the authenticated user's profile.
PATCH /api/v1/user/me
Authorization: Bearer <token>
{
"name": "Jane Doe"
}
Response 200:
{
"id": "usr_abc123",
"email": "user@example.com",
"name": "Jane Doe",
...
}
POST /user/me/password
Change the authenticated user's password.
POST /api/v1/user/me/password
Authorization: Bearer <token>
{
"current_password": "old-password",
"new_password": "new-strong-password"
}
Response 204: No Content
GET /user/api-keys
List the user's API keys.
GET /api/v1/user/api-keys
Authorization: Bearer <token>
Response 200:
{
"data": [
{
"id": "key_abc123",
"name": "CI/CD Integration",
"scopes": ["library:read", "sync:push"],
"last_used_at": "2026-01-10T15:30:00Z",
"created_at": "2026-01-01T00:00:00Z"
}
]
}
POST /user/api-keys
Create a new API key.
POST /api/v1/user/api-keys
Authorization: Bearer <token>
{
"name": "Backup Script",
"scopes": ["library:read", "file:read"]
}
Response 201:
{
"id": "key_def456",
"name": "Backup Script",
"key": "ebla_key_abc123def456...",
"scopes": ["library:read", "file:read"],
"created_at": "2026-01-11T10:00:00Z"
}
Note: The full key is only returned once at creation.
DELETE /user/api-keys/:id
Revoke an API key.
DELETE /api/v1/user/api-keys/key_abc123
Authorization: Bearer <token>
Response 204: No Content
Library Endpoints
GET /libraries
List all libraries accessible to the user.
GET /api/v1/libraries
Authorization: Bearer <token>
Query Parameters:
- limit (int): Max items to return (default 50)
- cursor (string): Pagination cursor
- filter (string): "owned", "shared", or "all" (default)
Response 200:
{
"data": [
{
"id": "lib_abc123",
"name": "My Documents",
"owner_id": "usr_abc123",
"owner_email": "user@example.com",
"team_id": null,
"file_count": 1523,
"total_size": 5368709120,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-11T10:00:00Z",
"permission": "owner"
}
],
"pagination": {
"cursor": "...",
"has_more": false,
"total": 5
}
}
POST /libraries
Create a new library.
POST /api/v1/libraries
Authorization: Bearer <token>
{
"name": "Project Files",
"team_id": "team_abc123" // optional
}
Response 201:
{
"id": "lib_def456",
"name": "Project Files",
"owner_id": "usr_abc123",
"team_id": "team_abc123",
"file_count": 0,
"total_size": 0,
"created_at": "2026-01-11T10:00:00Z"
}
GET /libraries/:id
Get library details.
GET /api/v1/libraries/lib_abc123
Authorization: Bearer <token>
Response 200:
{
"id": "lib_abc123",
"name": "My Documents",
"owner_id": "usr_abc123",
"owner_email": "user@example.com",
"team_id": null,
"file_count": 1523,
"total_size": 5368709120,
"block_count": 8432,
"dedup_ratio": 1.34,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-11T10:00:00Z",
"last_commit": {
"id": "cmt_xyz789",
"message": "Sync from laptop",
"created_at": "2026-01-11T09:45:00Z"
},
"permission": "owner",
"settings": {
"conflict_strategy": "lww",
"indexing_enabled": true
}
}
PATCH /libraries/:id
Update library settings.
PATCH /api/v1/libraries/lib_abc123
Authorization: Bearer <token>
{
"name": "Renamed Library",
"settings": {
"conflict_strategy": "three-way"
}
}
Response 200:
{
"id": "lib_abc123",
"name": "Renamed Library",
...
}
DELETE /libraries/:id
Delete a library. This removes all files and commits permanently.
DELETE /api/v1/libraries/lib_abc123
Authorization: Bearer <token>
Response 204: No Content
Deleting a library is irreversible. All files, commits, and associated data will be permanently removed.
File Endpoints
GET /libraries/:id/files
List files in a library at a specific path.
GET /api/v1/libraries/lib_abc123/files
Authorization: Bearer <token>
Query Parameters:
- path (string): Directory path (default "/")
- recursive (bool): Include subdirectories (default false)
- limit (int): Max items to return
- cursor (string): Pagination cursor
Response 200:
{
"data": [
{
"path": "/documents/report.pdf",
"name": "report.pdf",
"type": "file",
"size": 1048576,
"mime_type": "application/pdf",
"checksum": "sha256:abc123...",
"modified_at": "2026-01-10T14:30:00Z",
"created_at": "2026-01-05T09:00:00Z"
},
{
"path": "/documents/images",
"name": "images",
"type": "directory",
"size": 0,
"modified_at": "2026-01-10T12:00:00Z"
}
],
"pagination": { ... }
}
GET /libraries/:id/files/*path
Get metadata for a specific file.
GET /api/v1/libraries/lib_abc123/files/documents/report.pdf
Authorization: Bearer <token>
Response 200:
{
"path": "/documents/report.pdf",
"name": "report.pdf",
"type": "file",
"size": 1048576,
"mime_type": "application/pdf",
"checksum": "sha256:abc123def456...",
"blocks": ["blk_001", "blk_002", "blk_003"],
"modified_at": "2026-01-10T14:30:00Z",
"created_at": "2026-01-05T09:00:00Z",
"versions": 5,
"indexed": true,
"thumbnail_available": true
}
GET /libraries/:id/files/*path/download
Download a file's content.
GET /api/v1/libraries/lib_abc123/files/documents/report.pdf/download
Authorization: Bearer <token>
Response 200:
Content-Type: application/pdf
Content-Disposition: attachment; filename="report.pdf"
Content-Length: 1048576
[binary content]
GET /libraries/:id/files/*path/thumbnail
Get a thumbnail preview for supported file types (images, PDFs, videos).
GET /api/v1/libraries/lib_abc123/files/photos/vacation.jpg/thumbnail
Authorization: Bearer <token>
Query Parameters:
- size (string): "small" (100px), "medium" (300px), "large" (600px)
Response 200:
Content-Type: image/webp
[binary content]
DELETE /libraries/:id/files/*path
Delete a file or directory.
DELETE /api/v1/libraries/lib_abc123/files/documents/old-report.pdf
Authorization: Bearer <token>
Response 204: No Content
POST /libraries/:id/files/*path/move
Move or rename a file.
POST /api/v1/libraries/lib_abc123/files/documents/report.pdf/move
Authorization: Bearer <token>
{
"destination": "/archive/2025/report.pdf"
}
Response 200:
{
"path": "/archive/2025/report.pdf",
...
}
POST /libraries/:id/files/*path/copy
Copy a file to a new location.
POST /api/v1/libraries/lib_abc123/files/documents/template.docx/copy
Authorization: Bearer <token>
{
"destination": "/documents/new-doc.docx"
}
Response 201:
{
"path": "/documents/new-doc.docx",
...
}
Sync Endpoints
GET /libraries/:id/commits
List commits (sync snapshots) for a library.
GET /api/v1/libraries/lib_abc123/commits
Authorization: Bearer <token>
Query Parameters:
- limit (int): Max items to return
- cursor (string): Pagination cursor
- since (string): ISO timestamp to filter from
Response 200:
{
"data": [
{
"id": "cmt_xyz789",
"parent_id": "cmt_xyz788",
"message": "Sync from laptop",
"author_id": "usr_abc123",
"author_email": "user@example.com",
"device_name": "MacBook Pro",
"file_count": 1523,
"additions": 5,
"modifications": 2,
"deletions": 0,
"created_at": "2026-01-11T09:45:00Z"
}
],
"pagination": { ... }
}
GET /libraries/:id/commits/:commit_id
Get details of a specific commit including changed files.
GET /api/v1/libraries/lib_abc123/commits/cmt_xyz789
Authorization: Bearer <token>
Response 200:
{
"id": "cmt_xyz789",
"parent_id": "cmt_xyz788",
"message": "Sync from laptop",
"author_id": "usr_abc123",
"device_name": "MacBook Pro",
"created_at": "2026-01-11T09:45:00Z",
"changes": [
{
"path": "/documents/new-file.pdf",
"action": "added",
"size": 524288
},
{
"path": "/documents/report.pdf",
"action": "modified",
"size": 1048576,
"previous_size": 1024000
}
]
}
POST /libraries/:id/sync/push
Push local changes to the server. Used by the sync client.
POST /api/v1/libraries/lib_abc123/sync/push
Authorization: Bearer <token>
{
"parent_commit": "cmt_xyz788",
"message": "Sync from laptop",
"changes": [
{
"path": "/documents/new-file.pdf",
"action": "add",
"size": 524288,
"checksum": "sha256:abc123...",
"blocks": ["blk_001", "blk_002"]
}
]
}
Response 200:
{
"commit": {
"id": "cmt_xyz789",
"parent_id": "cmt_xyz788",
...
},
"blocks_needed": [] // blocks server doesn't have
}
Response 409 (conflict):
{
"error": {
"code": "conflict",
"message": "Server has newer changes",
"server_commit": "cmt_xyz790",
"conflicts": [
{
"path": "/documents/report.pdf",
"local_checksum": "sha256:abc...",
"server_checksum": "sha256:def..."
}
]
}
}
POST /libraries/:id/sync/pull
Pull changes from the server. Used by the sync client.
POST /api/v1/libraries/lib_abc123/sync/pull
Authorization: Bearer <token>
{
"from_commit": "cmt_xyz785",
"limit": 100
}
Response 200:
{
"commits": [
{
"id": "cmt_xyz786",
"parent_id": "cmt_xyz785",
"changes": [ ... ]
},
{
"id": "cmt_xyz787",
"parent_id": "cmt_xyz786",
"changes": [ ... ]
}
],
"has_more": false,
"head_commit": "cmt_xyz789"
}
POST /blocks/upload
Upload content blocks. Blocks are deduplicated by checksum.
POST /api/v1/blocks/upload
Authorization: Bearer <token>
Content-Type: multipart/form-data
Form fields:
- block[0].id: blk_001
- block[0].checksum: sha256:abc123...
- block[0].data: [binary]
- block[1].id: blk_002
- block[1].checksum: sha256:def456...
- block[1].data: [binary]
Response 200:
{
"uploaded": ["blk_001", "blk_002"],
"deduplicated": [] // blocks that already existed
}
GET /blocks/:id
Download a specific block.
GET /api/v1/blocks/blk_001
Authorization: Bearer <token>
Response 200:
Content-Type: application/octet-stream
[binary content]
Team Endpoints
GET /teams
List teams the user belongs to.
GET /api/v1/teams
Authorization: Bearer <token>
Response 200:
{
"data": [
{
"id": "team_abc123",
"name": "Engineering",
"member_count": 12,
"library_count": 5,
"role": "admin",
"created_at": "2026-01-01T00:00:00Z"
}
]
}
POST /teams
Create a new team.
POST /api/v1/teams
Authorization: Bearer <token>
{
"name": "Design Team"
}
Response 201:
{
"id": "team_def456",
"name": "Design Team",
"member_count": 1,
"library_count": 0,
"role": "owner",
"created_at": "2026-01-11T10:00:00Z"
}
GET /teams/:id
Get team details.
GET /api/v1/teams/team_abc123
Authorization: Bearer <token>
Response 200:
{
"id": "team_abc123",
"name": "Engineering",
"member_count": 12,
"library_count": 5,
"storage_used": 10737418240,
"created_at": "2026-01-01T00:00:00Z",
"settings": {
"default_library_permission": "viewer"
}
}
GET /teams/:id/members
List team members.
GET /api/v1/teams/team_abc123/members
Authorization: Bearer <token>
Response 200:
{
"data": [
{
"user_id": "usr_abc123",
"email": "alice@example.com",
"name": "Alice",
"role": "owner",
"joined_at": "2026-01-01T00:00:00Z"
},
{
"user_id": "usr_def456",
"email": "bob@example.com",
"name": "Bob",
"role": "member",
"joined_at": "2026-01-05T00:00:00Z"
}
]
}
POST /teams/:id/members
Add a member to the team.
POST /api/v1/teams/team_abc123/members
Authorization: Bearer <token>
{
"email": "newmember@example.com",
"role": "member"
}
Response 201:
{
"user_id": "usr_ghi789",
"email": "newmember@example.com",
"role": "member",
"joined_at": "2026-01-11T10:00:00Z"
}
PATCH /teams/:id/members/:user_id
Update a member's role.
PATCH /api/v1/teams/team_abc123/members/usr_def456
Authorization: Bearer <token>
{
"role": "admin"
}
Response 200:
{
"user_id": "usr_def456",
"role": "admin",
...
}
DELETE /teams/:id/members/:user_id
Remove a member from the team.
DELETE /api/v1/teams/team_abc123/members/usr_def456
Authorization: Bearer <token>
Response 204: No Content
POST /teams/:id/invitations
Create an invitation link.
POST /api/v1/teams/team_abc123/invitations
Authorization: Bearer <token>
{
"role": "member",
"expires_in": 604800, // 7 days in seconds
"max_uses": 10
}
Response 201:
{
"id": "inv_abc123",
"code": "TEAM-ABC-XYZ",
"url": "https://server:6333/join/TEAM-ABC-XYZ",
"role": "member",
"expires_at": "2026-01-18T10:00:00Z",
"max_uses": 10,
"uses": 0
}
Search Endpoints
GET /search
Search files across all accessible libraries.
GET /api/v1/search
Authorization: Bearer <token>
Query Parameters:
- q (string): Search query
- library_id (string): Limit to specific library (optional)
- type (string): Filter by file type (optional)
- limit (int): Max results (default 20)
Response 200:
{
"data": [
{
"library_id": "lib_abc123",
"library_name": "My Documents",
"path": "/documents/report.pdf",
"name": "report.pdf",
"type": "file",
"mime_type": "application/pdf",
"size": 1048576,
"modified_at": "2026-01-10T14:30:00Z",
"snippet": "...quarterly revenue increased by 15%...",
"score": 0.89
}
],
"total": 42
}
POST /search/semantic
Perform semantic (AI-powered) search using embeddings.
POST /api/v1/search/semantic
Authorization: Bearer <token>
{
"query": "documents about budget planning",
"library_ids": ["lib_abc123"],
"limit": 10,
"threshold": 0.7
}
Response 200:
{
"data": [
{
"library_id": "lib_abc123",
"path": "/finance/2026-budget.xlsx",
"name": "2026-budget.xlsx",
"similarity": 0.92,
"snippet": "Annual budget planning document with Q1-Q4 projections..."
}
]
}
POST /search/ask
Ask a natural language question about your files (AI Q&A with citations).
POST /api/v1/search/ask
Authorization: Bearer <token>
{
"question": "What was the Q3 revenue for the ACME project?",
"library_ids": ["lib_abc123", "lib_def456"]
}
Response 200:
{
"answer": "The Q3 revenue for the ACME project was $2.4 million, representing a 12% increase over Q2.",
"citations": [
{
"library_id": "lib_abc123",
"path": "/reports/acme-q3-summary.pdf",
"name": "acme-q3-summary.pdf",
"page": 3,
"excerpt": "ACME Project Q3 Results: Total revenue reached $2.4M, up 12% from Q2's $2.14M..."
}
],
"confidence": 0.94
}
Share Endpoints
GET /libraries/:id/shares
List sharing settings for a library.
GET /api/v1/libraries/lib_abc123/shares
Authorization: Bearer <token>
Response 200:
{
"users": [
{
"user_id": "usr_def456",
"email": "colleague@example.com",
"permission": "editor",
"granted_at": "2026-01-05T00:00:00Z"
}
],
"teams": [
{
"team_id": "team_abc123",
"name": "Engineering",
"permission": "viewer",
"granted_at": "2026-01-01T00:00:00Z"
}
],
"links": [
{
"id": "link_abc123",
"url": "https://server:6333/s/abc123xyz",
"permission": "viewer",
"password_protected": true,
"expires_at": "2026-02-01T00:00:00Z",
"access_count": 5,
"created_at": "2026-01-10T00:00:00Z"
}
]
}
POST /libraries/:id/shares/users
Share a library with a user.
POST /api/v1/libraries/lib_abc123/shares/users
Authorization: Bearer <token>
{
"email": "colleague@example.com",
"permission": "editor"
}
Response 201:
{
"user_id": "usr_def456",
"email": "colleague@example.com",
"permission": "editor",
"granted_at": "2026-01-11T10:00:00Z"
}
POST /libraries/:id/shares/links
Create a share link for a library or file.
POST /api/v1/libraries/lib_abc123/shares/links
Authorization: Bearer <token>
{
"path": "/documents/report.pdf", // optional, omit for library link
"permission": "viewer",
"password": "secret123", // optional
"expires_in": 604800 // optional, seconds until expiry
}
Response 201:
{
"id": "link_def456",
"url": "https://server:6333/s/def456xyz",
"path": "/documents/report.pdf",
"permission": "viewer",
"password_protected": true,
"expires_at": "2026-01-18T10:00:00Z",
"created_at": "2026-01-11T10:00:00Z"
}
DELETE /libraries/:id/shares/links/:link_id
Revoke a share link.
DELETE /api/v1/libraries/lib_abc123/shares/links/link_abc123
Authorization: Bearer <token>
Response 204: No Content
GET /s/:code
Access a shared resource via link (public endpoint).
GET /s/abc123xyz
Headers (if password protected):
X-Share-Password: secret123
Response 200 (file):
Content-Type: application/pdf
[binary content]
Response 200 (directory/library):
{
"type": "directory",
"name": "Shared Files",
"files": [
{
"path": "/report.pdf",
"name": "report.pdf",
"type": "file",
"size": 1048576
}
]
}
Admin Endpoints
These endpoints require admin privileges.
GET /admin/users
List all users.
GET /api/v1/admin/users
Authorization: Bearer <admin_token>
Response 200:
{
"data": [
{
"id": "usr_abc123",
"email": "user@example.com",
"name": "John Doe",
"is_admin": false,
"storage_used": 1073741824,
"storage_quota": 10737418240,
"library_count": 3,
"last_active_at": "2026-01-11T09:00:00Z",
"created_at": "2026-01-01T00:00:00Z"
}
],
"pagination": { ... }
}
POST /admin/users
Create a new user.
POST /api/v1/admin/users
Authorization: Bearer <admin_token>
{
"email": "newuser@example.com",
"password": "initial-password",
"name": "New User",
"is_admin": false,
"storage_quota": 10737418240
}
Response 201:
{
"id": "usr_new123",
"email": "newuser@example.com",
...
}
PATCH /admin/users/:id
Update a user's settings.
PATCH /api/v1/admin/users/usr_abc123
Authorization: Bearer <admin_token>
{
"storage_quota": 21474836480,
"is_admin": true
}
Response 200:
{
"id": "usr_abc123",
"storage_quota": 21474836480,
"is_admin": true,
...
}
DELETE /admin/users/:id
Delete a user and optionally their data.
DELETE /api/v1/admin/users/usr_abc123
Authorization: Bearer <admin_token>
Query Parameters:
- delete_data (bool): Also delete user's libraries (default false)
Response 204: No Content
GET /admin/stats
Get server statistics.
GET /api/v1/admin/stats
Authorization: Bearer <admin_token>
Response 200:
{
"users": {
"total": 150,
"active_today": 45,
"active_week": 120
},
"libraries": {
"total": 342,
"personal": 280,
"team": 62
},
"storage": {
"total_bytes": 1099511627776,
"used_bytes": 549755813888,
"block_count": 2847561,
"dedup_ratio": 1.42
},
"sync": {
"commits_today": 1523,
"active_connections": 78
}
}
POST /admin/backup
Trigger a manual backup.
POST /api/v1/admin/backup
Authorization: Bearer <admin_token>
{
"type": "full" // or "incremental"
}
Response 202:
{
"backup_id": "bak_abc123",
"status": "running",
"started_at": "2026-01-11T10:00:00Z"
}
GET /admin/backups
List backups.
GET /api/v1/admin/backups
Authorization: Bearer <admin_token>
Response 200:
{
"data": [
{
"id": "bak_abc123",
"type": "full",
"status": "completed",
"size_bytes": 5368709120,
"started_at": "2026-01-11T02:00:00Z",
"completed_at": "2026-01-11T02:45:00Z",
"path": "/backups/ebla-full-20260111.tar.gz"
}
]
}
POST /admin/gc
Trigger garbage collection.
POST /api/v1/admin/gc
Authorization: Bearer <admin_token>
{
"dry_run": true
}
Response 200:
{
"orphaned_blocks": 1523,
"reclaimable_bytes": 1073741824,
"dry_run": true
}
WebSocket API
Ebla uses WebSocket connections for real-time sync notifications.
Connection
wss://your-server:6333/api/v1/ws
?token=<access_token>
Message Format
All messages are JSON-encoded:
{
"type": "message_type",
"payload": { ... }
}
Client Messages
Subscribe to Library
{
"type": "subscribe",
"payload": {
"library_id": "lib_abc123"
}
}
Unsubscribe from Library
{
"type": "unsubscribe",
"payload": {
"library_id": "lib_abc123"
}
}
Ping (Keepalive)
{
"type": "ping"
}
Server Messages
New Commit
{
"type": "commit",
"payload": {
"library_id": "lib_abc123",
"commit": {
"id": "cmt_xyz789",
"parent_id": "cmt_xyz788",
"author_email": "colleague@example.com",
"device_name": "Desktop PC",
"additions": 3,
"modifications": 1,
"deletions": 0,
"created_at": "2026-01-11T10:15:00Z"
}
}
}
File Changed
{
"type": "file_changed",
"payload": {
"library_id": "lib_abc123",
"path": "/documents/report.pdf",
"action": "modified",
"commit_id": "cmt_xyz789"
}
}
Conflict Detected
{
"type": "conflict",
"payload": {
"library_id": "lib_abc123",
"path": "/documents/shared-doc.docx",
"local_version": "cmt_abc123",
"server_version": "cmt_def456"
}
}
Pong (Response to Ping)
{
"type": "pong"
}
Error
{
"type": "error",
"payload": {
"code": "subscription_failed",
"message": "You don't have access to this library"
}
}
Example: WebSocket Client
// JavaScript example
const ws = new WebSocket('wss://server:6333/api/v1/ws?token=' + accessToken);
ws.onopen = () => {
// Subscribe to library updates
ws.send(JSON.stringify({
type: 'subscribe',
payload: { library_id: 'lib_abc123' }
}));
};
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
switch (message.type) {
case 'commit':
console.log('New commit:', message.payload.commit.id);
// Trigger sync pull
break;
case 'conflict':
console.log('Conflict detected:', message.payload.path);
// Show conflict resolution UI
break;
}
};
// Send keepalive every 30 seconds
setInterval(() => {
ws.send(JSON.stringify({ type: 'ping' }));
}, 30000);
Rate Limits
API requests are rate-limited to ensure fair usage:
| Endpoint Category | Limit | Window |
|---|---|---|
| Authentication | 10 requests | 1 minute |
| Read operations | 1000 requests | 1 minute |
| Write operations | 100 requests | 1 minute |
| Block uploads | 50 MB | 1 minute |
| Search / AI | 30 requests | 1 minute |
Rate limit headers are included in responses:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 950
X-RateLimit-Reset: 1704967200
SDKs and Libraries
Official SDKs are planned for:
- Go
- Python
- JavaScript/TypeScript
- Rust
In the meantime, use standard HTTP libraries with the REST API documented above.