REST API
Integrate Kurpod into your applications using our comprehensive REST API. Full functionality available programmatically.
Overview
The Kurpod REST API provides complete access to all functionality:
- Base URL:
http://localhost:3000/api
- Authentication: Token-based (in headers)
- Content-Type:
application/json
- Responses: JSON with consistent structure
All file data is encrypted/decrypted client-side. The API handles encrypted blobs only.
Authentication
Unlock storage
Before accessing files, unlock your storage:
POST /api/unlock
Content-Type: application/json
{
"password": "your-secure-password"
}
Response:
{
"success": true,
"token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"volume": "standard",
"expires_in": 3600
}
Use the token in subsequent requests:
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGc...
Create new storage
Initialize a new encrypted storage:
POST /api/create
Content-Type: application/json
{
"password_standard": "standard-password",
"password_hidden": "hidden-password", // Optional
"enable_hidden": true // Optional
}
File operations
List files
Get directory contents:
GET /api/files?path=/folder/subfolder
Authorization: Bearer <token>
Response:
{
"success": true,
"data": {
"path": "/folder/subfolder",
"items": [
{
"name": "document.pdf",
"type": "file",
"size": 1048576,
"modified": "2024-01-15T10:30:00Z",
"encrypted_id": "a3f4b2c1..."
},
{
"name": "photos",
"type": "directory",
"size": 0,
"modified": "2024-01-14T15:20:00Z",
"encrypted_id": "b5e6d3a2..."
}
]
}
}
Upload file
Upload an encrypted file:
POST /api/files/upload
Authorization: Bearer <token>
Content-Type: multipart/form-data
------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="encrypted.bin"
Content-Type: application/octet-stream
<encrypted file data>
------WebKitFormBoundary
Content-Disposition: form-data; name="metadata"
{
"path": "/documents",
"encrypted_name": "ZG9jdW1lbnQucGRm",
"nonce": "base64_nonce",
"size": 1048576
}
------WebKitFormBoundary--
Download file
Retrieve an encrypted file:
GET /api/files/download/{encrypted_id}
Authorization: Bearer <token>
Returns raw encrypted binary data with headers:
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="encrypted.bin"
X-Encrypted-Name: ZG9jdW1lbnQucGRm
X-Nonce: base64_nonce
Delete file
Remove a file or directory:
DELETE /api/files/{encrypted_id}
Authorization: Bearer <token>
Move/Rename
Move or rename files:
PUT /api/files/{encrypted_id}/move
Authorization: Bearer <token>
Content-Type: application/json
{
"new_path": "/new/location",
"new_name": "renamed.pdf"
}
Create directory
Create a new folder:
POST /api/files/directory
Authorization: Bearer <token>
Content-Type: application/json
{
"path": "/parent/folder",
"name": "new-folder"
}
Volume management
Switch volume
Switch between standard and hidden volumes:
POST /api/volume/switch
Authorization: Bearer <token>
Content-Type: application/json
{
"password": "hidden-volume-password"
}
Volume info
Get current volume information:
GET /api/volume/info
Authorization: Bearer <token>
Response:
{
"success": true,
"data": {
"type": "standard",
"size_used": 104857600,
"size_total": 1073741824,
"file_count": 42,
"created": "2024-01-01T00:00:00Z"
}
}
System operations
Server status
Check server health:
GET /api/status
Response:
{
"success": true,
"data": {
"version": "1.0.0",
"uptime": 3600,
"blob_loaded": true,
"locked": false
}
}
Compact storage
Reclaim space by compacting the blob:
POST /api/compact
Authorization: Bearer <token>
Content-Type: application/json
{
"password_standard": "standard-password",
"password_hidden": "hidden-password" // If hidden volume exists
}
Lock storage
Immediately lock the storage:
POST /api/lock
Authorization: Bearer <token>
Search
Search files
Search for files by name:
GET /api/search?q=budget&path=/documents
Authorization: Bearer <token>
Response:
{
"success": true,
"data": {
"query": "budget",
"results": [
{
"name": "budget-2024.xlsx",
"path": "/documents/finance",
"type": "file",
"size": 524288,
"encrypted_id": "c7f8e9d0..."
}
],
"count": 1
}
}
Batch operations
Multiple file upload
Upload multiple files at once:
POST /api/files/upload/batch
Authorization: Bearer <token>
Content-Type: application/json
{
"files": [
{
"path": "/documents",
"name": "file1.pdf",
"data": "base64_encrypted_data",
"nonce": "base64_nonce"
},
{
"path": "/photos",
"name": "image.jpg",
"data": "base64_encrypted_data",
"nonce": "base64_nonce"
}
]
}
Batch delete
Delete multiple items:
DELETE /api/files/batch
Authorization: Bearer <token>
Content-Type: application/json
{
"ids": ["a3f4b2c1...", "b5e6d3a2...", "c7f8e9d0..."]
}
Error handling
All errors follow a consistent format:
{
"success": false,
"error": {
"code": "AUTH_FAILED",
"message": "Invalid password",
"details": {}
}
}
Common error codes:
AUTH_FAILED
: Authentication failedTOKEN_EXPIRED
: Token has expiredNOT_FOUND
: Resource not foundALREADY_EXISTS
: Resource already existsSTORAGE_FULL
: Storage capacity exceededINVALID_REQUEST
: Malformed requestSERVER_ERROR
: Internal server error
Rate limiting
API endpoints are rate-limited to prevent abuse:
- Authentication: 10 attempts per minute
- File operations: 100 requests per minute
- Search: 30 requests per minute
- System operations: 5 requests per minute
Headers indicate rate limit status:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1673612400
Client libraries
JavaScript/TypeScript
class KurpodClient {
constructor(baseUrl = 'http://localhost:3000') {
this.baseUrl = baseUrl;
this.token = null;
}
async unlock(password) {
const response = await fetch(`${this.baseUrl}/api/unlock`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ password })
});
const data = await response.json();
if (data.success) {
this.token = data.token;
}
return data;
}
async listFiles(path = '/') {
const response = await fetch(
`${this.baseUrl}/api/files?path=${encodeURIComponent(path)}`,
{
headers: { 'Authorization': `Bearer ${this.token}` }
}
);
return response.json();
}
async uploadFile(file, path, encryptedData, nonce) {
const formData = new FormData();
formData.append('file', new Blob([encryptedData]));
formData.append('metadata', JSON.stringify({
path,
encrypted_name: btoa(file.name),
nonce: btoa(nonce),
size: file.size
}));
const response = await fetch(`${this.baseUrl}/api/files/upload`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${this.token}` },
body: formData
});
return response.json();
}
}
// Usage
const client = new KurpodClient();
await client.unlock('my-secure-password');
const files = await client.listFiles('/documents');
Python
import requests
import base64
from typing import Optional, Dict, Any
class KurpodClient:
def __init__(self, base_url: str = "http://localhost:3000"):
self.base_url = base_url
self.token: Optional[str] = None
self.session = requests.Session()
def unlock(self, password: str) -> Dict[str, Any]:
response = self.session.post(
f"{self.base_url}/api/unlock",
json={"password": password}
)
data = response.json()
if data["success"]:
self.token = data["token"]
self.session.headers.update({
"Authorization": f"Bearer {self.token}"
})
return data
def list_files(self, path: str = "/") -> Dict[str, Any]:
response = self.session.get(
f"{self.base_url}/api/files",
params={"path": path}
)
return response.json()
def upload_file(
self,
file_path: str,
encrypted_data: bytes,
nonce: bytes,
remote_path: str = "/"
) -> Dict[str, Any]:
files = {
"file": ("encrypted.bin", encrypted_data, "application/octet-stream")
}
metadata = {
"path": remote_path,
"encrypted_name": base64.b64encode(file_path.encode()).decode(),
"nonce": base64.b64encode(nonce).decode(),
"size": len(encrypted_data)
}
response = self.session.post(
f"{self.base_url}/api/files/upload",
files=files,
data={"metadata": json.dumps(metadata)}
)
return response.json()
# Usage
client = KurpodClient()
client.unlock("my-secure-password")
files = client.list_files("/documents")
Go
package kurpod
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
type Client struct {
BaseURL string
Token string
client *http.Client
}
func NewClient(baseURL string) *Client {
return &Client{
BaseURL: baseURL,
client: &http.Client{},
}
}
func (c *Client) Unlock(password string) error {
payload := map[string]string{"password": password}
data, _ := json.Marshal(payload)
resp, err := c.client.Post(
c.BaseURL+"/api/unlock",
"application/json",
bytes.NewBuffer(data),
)
if err != nil {
return err
}
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
if token, ok := result["token"].(string); ok {
c.Token = token
}
return nil
}
func (c *Client) ListFiles(path string) ([]FileInfo, error) {
req, _ := http.NewRequest("GET", c.BaseURL+"/api/files", nil)
req.Header.Set("Authorization", "Bearer "+c.Token)
q := req.URL.Query()
q.Add("path", path)
req.URL.RawQuery = q.Encode()
resp, err := c.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result struct {
Data struct {
Items []FileInfo `json:"items"`
} `json:"data"`
}
json.NewDecoder(resp.Body).Decode(&result)
return result.Data.Items, nil
}
WebSocket API
For real-time updates, connect to the WebSocket endpoint:
const ws = new WebSocket('ws://localhost:3000/ws');
ws.onopen = () => {
ws.send(JSON.stringify({
type: 'auth',
token: 'your-jwt-token'
}));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
switch (data.type) {
case 'file_uploaded':
console.log('New file:', data.file);
break;
case 'file_deleted':
console.log('File removed:', data.id);
break;
}
};
Events:
file_uploaded
: New file addedfile_deleted
: File removedfile_moved
: File relocatedstorage_locked
: Storage lockedcompact_progress
: Compaction status
Best practices
- Always encrypt client-side before sending to API
- Use HTTPS in production to protect tokens
- Handle token expiration gracefully
- Implement exponential backoff for retries
- Validate responses before processing
- Clear tokens on logout/error
- Use batch operations for multiple files
- Monitor rate limits to avoid throttling
- Cache directory listings when possible
- Compress large uploads before encryption
For more details, see our API examples repository.