API Reference
Base URL: http://<your-server-ip-or-domain>:8080
Authentication
All business endpoints require this header:
| Header | Value | Required |
|---|---|---|
X-API-Key | Your API key | ✅ |
Security note
Never hardcode the API key in frontend code. Use it in backend services or CI pipelines.
Async Task Flow
POST compress → returns task_id
GET tasks/{id} → pending / processing / completed / failed
GET download → download the result file| status | Meaning | Action |
|---|---|---|
pending | Queued | Keep polling |
processing | In progress | Keep polling |
completed | Done | Call download |
failed | Failed | Check the error field |
1. System Status
GET /api/v1/health
No authentication required.
Response 200
{ "status": "healthy", "version": "2.1.0", "uptime_seconds": 3600, "active_tasks": 0, "queue_length": 0 }GET /api/v1/capabilities
Query the capabilities supported by this service.
Response 200
{
"engines": {
"draco": { "available": true, "version": "…", "binary_path": "…" },
"meshopt": { "available": true, "version": "…", "binary_path": "…" }
},
"formats": {
"input": ["glb", "gltf", "obj", "fbx", "stl", "dae", "ply"],
"output": ["glb", "gltf", "obj", "stl", "ply"]
},
"license": { "authorized": true, "tier": 1, "status": "active" }
}2. Model Compression
POST /api/v1/compress
Submit a compression task.
Headers
| Header | Value |
|---|---|
| Content-Type | multipart/form-data |
| X-API-Key | Your key |
Body (form-data)
| Field | Type | Required | Description |
|---|---|---|---|
file | File | ✅ | Model file (GLB/glTF/OBJ/FBX, etc.) |
engine | string | ✅ | draco or meshopt |
level | integer | ❌ | Compression level 0–10 (0 = RAW, no compression), default 7. Higher = better compression |
position_quantization_bits | integer | ❌ | Position precision (Draco only), default 14, range 8–24 |
normal_quantization_bits | integer | ❌ | Normal precision (Draco only), default 10 |
texcoord_quantization_bits | integer | ❌ | UV precision (Draco only), default 12 |
color_quantization_bits | integer | ❌ | Color precision (Draco only), default 8 |
generic_quantization_bits | integer | ❌ | Generic attribute precision (Draco only), default 12 |
meshopt_compression_level | string | ❌ | Meshopt level: high / medium / low, default high |
Response 200
{
"task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "pending",
"message": "Task submitted, queued"
}3. Format Conversion
POST /api/v1/convert
Convert a model from one format to another.
Headers
| Header | Value |
|---|---|
| Content-Type | multipart/form-data |
| X-API-Key | Your key |
Body (form-data)
| Field | Type | Required | Description |
|---|---|---|---|
file | File | ✅ | Model file |
target_format | string | ✅ | glb / gltf / obj / fbx / stl / dae / ply |
When the target is
gltf, the output is a.zipbundle (containing the .gltf + .bin + textures).
Response 200
{
"task_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"status": "pending"
}4. Model Repair
POST /api/v1/repair
Automatically removes empty nodes, fixes normals, merges duplicate vertices, drops degenerate faces, etc.
Headers
| Header | Value |
|---|---|
| Content-Type | multipart/form-data |
| X-API-Key | Your key |
Body (form-data)
| Field | Type | Required | Description |
|---|---|---|---|
file | File | ✅ | Model file |
Response 200
{
"task_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
"status": "pending"
}5. Model Diagnosis (Planned)
POST /api/v1/diagnose
The endpoint is reserved; this version returns 501 (not yet implemented). Model health checks are currently available only in the desktop app.
6. Texture Optimization
POST /api/v1/textures/optimize
Compress model textures or standalone images to JPEG/WebP/PNG.
Headers
| Header | Value |
|---|---|
| Content-Type | multipart/form-data |
| X-API-Key | Your key |
Body (form-data)
| Field | Type | Required | Description |
|---|---|---|---|
file | File | ✅ | Model file or standalone image |
format | string | ✅ | jpeg / webp / png |
quality | integer | ❌ | Quality 1–100, default 82 (JPEG/WebP); PNG compression level 1–9, default 6 |
Response 200
{
"task_id": "d4e5f6a7-b8c9-0123-defa-234567890123",
"status": "pending"
}POST /api/v1/textures/ktx2
The endpoint is reserved; this version returns 501 (KTX2 encoding not yet implemented). KTX2 encoding is currently available only in the desktop app.
7. Task Management
GET /api/v1/tasks/{task_id}
Query task status and progress by task_id.
Path parameters
| Parameter | Type | Description |
|---|---|---|
task_id | string | Unique task identifier |
Response 200 — in progress
{
"task_id": "a1b2c3d4-...",
"status": "processing",
"progress": 65,
"created_at": "2026-08-03T10:30:00Z",
"started_at": "2026-08-03T10:30:01Z",
"type": "compress",
"input_filename": "model.glb",
"input_size_bytes": 15728640
}Response 200 — completed
{
"task_id": "a1b2c3d4-...",
"status": "completed",
"progress": 100,
"created_at": "2026-08-03T10:30:00Z",
"completed_at": "2026-08-03T10:30:05Z",
"type": "compress",
"input_filename": "model.glb",
"input_size_bytes": 15728640,
"output": {
"filename": "model_optimized.glb",
"size_bytes": 3145728,
"compression_ratio": 0.20,
"savings_percent": 80.0
}
}Response 200 — failed
{
"task_id": "a1b2c3d4-...",
"status": "failed",
"error": "draco_transcoder execution failed: exit code 1",
"created_at": "2026-08-03T10:30:00Z",
"failed_at": "2026-08-03T10:30:02Z"
}Response field reference
| Field | Type | Description |
|---|---|---|
task_id | string | Unique task identifier |
status | string | pending / processing / completed / failed |
progress | integer | Progress 0–100 |
type | string | compress / convert / repair / diagnose / texture_optimize / texture_ktx2 |
input_filename | string | Original file name |
input_size_bytes | integer | Original size (bytes) |
output.filename | string | Output file name (when completed) |
output.size_bytes | integer | Output size in bytes (when completed) |
output.compression_ratio | float | Compression ratio (compress/texture tasks) |
output.savings_percent | float | Size reduction percentage (compress/texture tasks) |
error | string | Error reason (when failed) |
created_at | string | Creation time, ISO 8601 |
started_at | string | Start time |
completed_at / failed_at | string | Finish time |
GET /api/v1/tasks/{task_id}/download
Download the processed result file.
Path parameters
| Parameter | Type | Description |
|---|---|---|
task_id | string | ID of a completed task |
Response 200
Returns the file as a binary stream (Content-Type: application/octet-stream).
8. Batch Processing
POST /api/v1/batch/compress
Submit multiple files for compression in one request; each file becomes an independent sub-task.
Headers
| Header | Value |
|---|---|
| Content-Type | multipart/form-data |
| X-API-Key | Your key |
Body (form-data)
| Field | Type | Required | Description |
|---|---|---|---|
files | File[] | ✅ | Multiple model files |
engine | string | ✅ | draco or meshopt |
level | integer | ❌ | Compression level 1–10, default 7 |
Response 200
{
"batch_id": "batch-abc123",
"total": 3,
"tasks": [
{ "task_id": "t1-...", "filename": "model1.glb", "status": "pending" },
{ "task_id": "t2-...", "filename": "model2.fbx", "status": "pending" },
{ "task_id": "t3-...", "filename": "scene.gltf", "status": "pending" }
]
}GET /api/v1/batch/{batch_id}
Query the overall progress of a batch.
Path parameters
| Parameter | Type | Description |
|---|---|---|
batch_id | string | Unique batch identifier |
Response 200
{
"batch_id": "batch-abc123",
"status": "processing",
"total": 3, "completed": 1, "failed": 0,
"tasks": [
{ "task_id": "t1-...", "filename": "model1.glb", "status": "completed" },
{ "task_id": "t2-...", "filename": "model2.fbx", "status": "processing" },
{ "task_id": "t3-...", "filename": "scene.gltf", "status": "pending" }
]
}Sub-tasks can be operated individually via task query and result download.
9. Licensing
POST /api/v1/license/verify
Verify whether a License Key is valid.
Body (JSON)
{ "license_key": "xxxx-xxxx-xxxx-xxxx" }Response 200
{
"success": true,
"message": "license valid",
"expires_at": 1796064000
}
expires_atis a Unix timestamp (seconds). This endpoint is intended for administration.
GET /api/v1/license/info
Query the current license status.
Response 200
{
"authorized": true,
"server_fingerprint": "a1b2c3d4e5f6…",
"status": "active",
"license_expires_at": 1796064000,
"tier": 1,
"days_until_expiry": 365,
"machine_id": "server-machine-id"
}
tier: 0 = not licensed (trial limits), 1/2 = licensed tiers;license_expires_atis a Unix timestamp (seconds).
10. Monitoring
GET /api/v1/metrics
Prometheus-format metrics for Grafana integration.
| Metric | Meaning |
|---|---|
zipoly_requests_total | Total requests |
zipoly_active_tasks | Current concurrent task count |
zipoly_queue_length | Tasks waiting in the queue |
zipoly_task_processing_duration_seconds | Task processing duration distribution |
zipoly_tasks_completed_total | Total completed tasks |
zipoly_tasks_failed_total | Total failed tasks |
zipoly_errors_total | Total errors |
Error Codes
| HTTP | Meaning | Typical scenario |
|---|---|---|
| 400 | Bad request | Unsupported format, missing required field |
| 402 | License limit exceeded | File exceeds the plan's size/batch limit, or the license has expired |
| 401 | Unauthorized | Missing/wrong X-API-Key |
| 404 | Not found | Invalid task_id / batch_id |
| 500 | Internal error | Engine execution failure, insufficient disk |
Error response format
{ "error": "error description" }| Scenario | Example |
|---|---|
| Unsupported format | { "error": "unsupported format: .max" } |
| Missing required field | { "error": "missing required field: engine" } |
| Unauthorized | { "error": "unauthorized: missing or invalid X-API-Key header" } |
| Limit exceeded | { "error": "file size 512MB exceeds limit of 500MB for current license tier" } |
| Internal error | { "error": "internal error: draco_transcoder execution failed" } |
Other Endpoints
Besides the business endpoints above, the server also exposes endpoints used by the web admin console (/config, /events SSE, /auth/me, /admin/*, etc.). They are rarely called directly and are not covered here.