Skip to content

API Reference

Base URL: http://<your-server-ip-or-domain>:8080

Authentication

All business endpoints require this header:

HeaderValueRequired
X-API-KeyYour 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
statusMeaningAction
pendingQueuedKeep polling
processingIn progressKeep polling
completedDoneCall download
failedFailedCheck the error field

1. System Status

GET /api/v1/health

No authentication required.

Response 200

json
{ "status": "ok" }

GET /api/v1/capabilities

Query the capabilities supported by this service.

Response 200

json
{
  "engines": ["draco", "meshopt"],
  "formats": ["glb", "gltf", "obj", "fbx", "stl", "dae", "ply"],
  "features": ["compress", "convert", "repair", "diagnose", "texture_optimize", "texture_ktx2"]
}

2. Model Compression

POST /api/v1/compress

Submit a compression task.

Headers

HeaderValue
Content-Typemultipart/form-data
X-API-KeyYour key

Body (form-data)

FieldTypeRequiredDescription
fileFileModel file (GLB/glTF/OBJ/FBX, etc.)
enginestringdraco or meshopt
levelintegerCompression level 1–10, default 7. Higher = better compression
position_quantization_bitsintegerPosition precision (Draco only), default 14, range 8–24
normal_quantization_bitsintegerNormal precision (Draco only), default 10
texcoord_quantization_bitsintegerUV precision (Draco only), default 12
color_quantization_bitsintegerColor precision (Draco only), default 8
generic_quantization_bitsintegerGeneric attribute precision (Draco only), default 12
meshopt_compression_levelstringMeshopt level: high / medium / low, default high

Response 200

json
{
  "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

HeaderValue
Content-Typemultipart/form-data
X-API-KeyYour key

Body (form-data)

FieldTypeRequiredDescription
fileFileModel file
target_formatstringglb / gltf / obj / fbx / stl / dae / ply

When the target is gltf, the output is a .zip bundle (containing the .gltf + .bin + textures).

Response 200

json
{
  "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

HeaderValue
Content-Typemultipart/form-data
X-API-KeyYour key

Body (form-data)

FieldTypeRequiredDescription
fileFileModel file

Response 200

json
{
  "task_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
  "status": "pending"
}

5. Model Diagnosis

POST /api/v1/diagnose

Runs a full health check on the model and produces a detailed report (does not modify the original file).

Headers

HeaderValue
Content-Typemultipart/form-data
X-API-KeyYour key

Body (form-data)

FieldTypeRequiredDescription
fileFileModel file

Response 200 (after the task completes)

The diagnosis result is embedded in the result field of the task query response:

json
{
  "result": {
    "format": "glb",
    "version": "2.0",
    "file_size_bytes": 15728640,
    "meshes": [{
      "name": "Mesh_0",
      "vertices": 24568,
      "triangles": 48192,
      "has_normals": true,
      "has_texcoords": true,
      "has_colors": false,
      "has_tangents": true,
      "skinned": false,
      "morph_targets": 0,
      "issues": [
        { "type": "degenerate_faces", "count": 12, "severity": "low" },
        { "type": "duplicate_vertices", "count": 234, "severity": "medium" }
      ]
    }],
    "textures": [
      { "name": "baseColorTexture", "format": "jpeg", "width": 2048, "height": 2048, "size_kb": 512 }
    ],
    "animations": [],
    "total_issues": 246,
    "recommendations": ["Consider running repair to fix degenerate faces and duplicate vertices"]
  }
}

6. Texture Optimization

POST /api/v1/textures/optimize

Compress model textures or standalone images to JPEG/WebP/PNG.

Headers

HeaderValue
Content-Typemultipart/form-data
X-API-KeyYour key

Body (form-data)

FieldTypeRequiredDescription
fileFileModel file or standalone image
formatstringjpeg / webp / png
qualityintegerQuality 1–100, default 82 (JPEG/WebP); PNG compression level 1–9, default 6

Response 200

json
{
  "task_id": "d4e5f6a7-b8c9-0123-defa-234567890123",
  "status": "pending"
}

POST /api/v1/textures/ktx2

KTX2 (Basis Universal) encoding — loads directly on the GPU, common for Web3D.

Headers

HeaderValue
Content-Typemultipart/form-data
X-API-KeyYour key

Body (form-data)

FieldTypeRequiredDescription
fileFileModel file or image (PNG/JPEG)
uastcbooleanUASTC high-quality mode, default false (ETC1S)
qualityintegerETC1S: 1–255, default 128; UASTC: 0–4, default 2

Response 200

json
{
  "task_id": "e5f6a7b8-c9d0-1234-efab-345678901234",
  "status": "pending"
}

ETC1S vs UASTC

ETC1S (default)UASTC
Compression ratioHigh (~1/10)Medium (~1/4)
Visual qualitySlight blur on complex texturesNear-original quality
Best forMobile / size-sensitiveDesktop / high fidelity

7. Task Management

GET /api/v1/tasks/{task_id}

Query task status and progress by task_id.

Path parameters

ParameterTypeDescription
task_idstringUnique task identifier

Response 200 — in progress

json
{
  "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

json
{
  "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

json
{
  "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

FieldTypeDescription
task_idstringUnique task identifier
statusstringpending / processing / completed / failed
progressintegerProgress 0–100
typestringcompress / convert / repair / diagnose / texture_optimize / texture_ktx2
input_filenamestringOriginal file name
input_size_bytesintegerOriginal size (bytes)
output.filenamestringOutput file name (when completed)
output.size_bytesintegerOutput size in bytes (when completed)
output.compression_ratiofloatCompression ratio (compress/texture tasks)
output.savings_percentfloatSize reduction percentage (compress/texture tasks)
errorstringError reason (when failed)
created_atstringCreation time, ISO 8601
started_atstringStart time
completed_at / failed_atstringFinish time

GET /api/v1/tasks/{task_id}/download

Download the processed result file.

Path parameters

ParameterTypeDescription
task_idstringID 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

HeaderValue
Content-Typemultipart/form-data
X-API-KeyYour key

Body (form-data)

FieldTypeRequiredDescription
filesFile[]Multiple model files
enginestringdraco or meshopt
levelintegerCompression level 1–10, default 7

Response 200

json
{
  "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

ParameterTypeDescription
batch_idstringUnique batch identifier

Response 200

json
{
  "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)

json
{ "license_key": "xxxx-xxxx-xxxx-xxxx" }

Response 200

json
{
  "valid": true,
  "tier": "pro",
  "expires_at": "2027-08-03T00:00:00Z",
  "limits": { "max_file_size_mb": 500, "max_batch_count": 100 }
}

GET /api/v1/license/info

Query the current license status.

Response 200

json
{
  "mode": "licensed",
  "tier": "enterprise",
  "license_key": "****-****-****-1234",
  "expires_at": "2027-12-31T00:00:00Z",
  "trial": { "enabled": true, "used_files": 12, "max_files": 50 },
  "limits": {
    "max_file_size_mb": 500,
    "max_batch_count": -1,
    "max_texture_size_mb": 500
  }
}

-1 means unlimited.


10. Monitoring

GET /api/v1/metrics

Prometheus-format metrics for Grafana integration.

MetricMeaning
zipoly_tasks_totalTotal tasks (by type/status)
zipoly_task_duration_secondsTask duration distribution
zipoly_files_processed_totalTotal files processed
zipoly_compression_ratioCompression ratio distribution
zipoly_active_tasks_gaugeCurrent concurrent task count

Error Codes

HTTPMeaningTypical scenario
400Bad requestUnsupported format, missing required field
401UnauthorizedMissing/wrong X-API-Key
404Not foundInvalid task_id / batch_id
413Payload too largeExceeds the plan limit
429Rate limitedExceeded requests per minute
500Internal errorEngine execution failure, insufficient disk

Error response format

json
{ "error": "error description" }
ScenarioExample
Unsupported format{ "error": "unsupported format: .max" }
Missing required field{ "error": "missing required field: engine" }
Unauthorized{ "error": "unauthorized: missing or invalid X-API-Key header" }
File too large{ "error": "file size 512MB exceeds limit of 500MB for current license tier" }
Rate limited{ "error": "rate limit exceeded: max 60 requests per minute per API key" }
Internal error{ "error": "internal error: draco_transcoder execution failed" }

Rate Limiting

Each key is limited to 60 requests per minute. Exceeding it returns 429 with these response headers:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1691123456

Adjustable via ZIPOLY__SERVER__RATE_LIMIT_PER_MINUTE — see Configuration.

Built for Web3D developers