Models Reference
This page lists the main public response models used by the API.
ErrorResponse
All error responses share this envelope. Some errors include additional context fields.
| Field | Type | Required | Description |
|---|
error | string | yes | Machine-readable error code (e.g. "request.empty_file") |
detail | string|null | yes | Human-readable explanation |
Additional fields may appear depending on the error code. See Errors for full examples.
Example:
{
"error": "request.invalid_extension",
"detail": "File extension '.mp3' is not accepted by this compressor."
}
JobAcceptedResponse (POST /compress)
| Field | Type | Required | Description |
|---|
id | string | yes | Unique job identifier (GUIDv7) |
status | string | yes | Initial status ("Queued") |
fileName | string | yes | Original filename stem (without extension) |
format | string | yes | Compression format (e.g. "jpg", "png", "pdf") |
stats.inputP50Bytes | number|null | yes | Median input size from recent jobs (null if no history) |
stats.inputMeanBytes | number|null | yes | Mean input size from recent jobs (null if no history) |
stats.sampleCount | number | yes | Number of recent jobs in the stats sample |
stats.asOfUtc | string|null | no | When the stats snapshot was computed (ISO 8601) |
stats.validUntilUtc | string|null | no | When the stats snapshot expires (ISO 8601) |
timeline.uploadStartedAt | string | yes | Upload start timestamp (ISO 8601) |
timeline.uploadFinishedAt | string | yes | Upload finish timestamp (ISO 8601) |
timeline.queuedAt | string | yes | When the job entered the queue (ISO 8601) |
queue.pool | string | yes | Worker pool name (e.g. "ImagePool") |
queue.position | number | yes | Position in the queue |
queue.weight | number | yes | Scheduling weight for this job |
queue.totalQueued | number | yes | Total jobs currently queued in this pool |
queue.estimate | string|null | no | Estimated wait time (e.g. "< 5s") |
metrics.inputBytes | number|null | yes | Input file size in bytes (null if not yet measured) |
metrics.uploadMs | number | yes | Upload duration in milliseconds |
metrics.processingMs | number | yes | Processing duration in milliseconds (0 at submission) |
metrics.totalMs | number | yes | Total elapsed time in milliseconds |
Example -- JPG compression accepted:
{
"id": "0195e2a0-1234-7000-8000-000000000001",
"status": "Queued",
"fileName": "photo",
"format": "jpg",
"stats": {
"inputP50Bytes": 4200000,
"inputMeanBytes": 5100000,
"sampleCount": 128,
"asOfUtc": "2026-02-23T10:00:00Z",
"validUntilUtc": "2026-02-23T10:05:00Z"
},
"timeline": {
"uploadStartedAt": "2026-02-23T10:01:00.000Z",
"uploadFinishedAt": "2026-02-23T10:01:00.450Z",
"queuedAt": "2026-02-23T10:01:00.460Z"
},
"queue": {
"pool": "ImagePool",
"position": 3,
"weight": 2.5,
"totalQueued": 7,
"estimate": "< 5s"
},
"metrics": {
"inputBytes": 10333959,
"uploadMs": 450,
"processingMs": 0,
"totalMs": 460
}
}
JobStatusResponse (GET /compress/job/{id})
| Field | Type | Required | Description |
|---|
id | string | yes | Job identifier |
status | string | yes | "Queued", "Running", "Succeeded", "Failed", or "Canceled" |
format | string | yes | Compression format (e.g. "jpg", "png", "pdf") |
progress.percent | number | yes | Completion percentage (0--100) |
progress.phase | string|null | no | Current processing phase |
metrics.inputBytes | number | yes | Input file size in bytes |
metrics.outputBytes | number | yes | Output file size in bytes |
metrics.creditCost | number | yes | Credits charged for this job |
metrics.compressionRatio | number|null | no | Compressed / original ratio (e.g. 0.33) |
metrics.savingsPercent | number|null | no | Space savings percentage (e.g. 66.9) |
error | object|null | no | Error details (failed jobs only) |
error.code | string | — | Machine-readable failure code |
error.detail | string | — | Human-readable failure detail |
output | object|null | no | Output file summary (succeeded jobs only) |
output.fileName | string | — | Output filename |
output.contentType | string | — | MIME type of the output |
output.fileCount | number | — | Number of output files |
Example -- Succeeded JPG compression:
{
"id": "0195e2a0-1234-7000-8000-000000000001",
"status": "Succeeded",
"format": "jpg",
"progress": {
"percent": 100,
"phase": null
},
"metrics": {
"inputBytes": 10333959,
"outputBytes": 3421187,
"creditCost": 1,
"compressionRatio": 0.33,
"savingsPercent": 66.9
},
"error": null,
"output": {
"fileName": "photo-compressed.jpg",
"contentType": "image/jpeg",
"fileCount": 1
}
}
GetCompressorsResponse (GET /compress/compressors)
| Field | Type | Required | Description |
|---|
compressors | CompressorItem[] | yes | List of all available compressors |
sourceFormatTo | object | yes | Format graph: source format → list of output options with costing |
maxFileSizeBytes | number | yes | Global max file size for current tier |
maxConcurrentJobs | number | yes | Global max concurrent jobs for current tier |
maxBatchFiles | number | yes | Global max batch files for current tier |
CompressorItem
| Field | Type | Required | Description |
|---|
job | string | yes | Job type identifier (e.g. "image.jpg-compress") |
category | string | yes | Category ("images" or "documents") |
costing | DiscoveryCostingInfo | yes | Costing strategy and rates |
endpoint | string | yes | Submission endpoint ("/api/compress") |
inputFormats | string[] | yes | Accepted formats (dotless: ["jpg", "jpeg"]) |
outputFormats | string[] | yes | Output formats (dotless: ["jpg"]) |
maxFileSizeBytes | number | yes | Max file size for current tier |
maxConcurrentJobs | number | yes | Max concurrent jobs for current tier |
| Field | Type | Required | Description |
|---|
sourceFormat | string | yes | Input format (e.g. "jpg") |
targetFormat | string | yes | Output format (e.g. "jpg") |
job | string | yes | Job type identifier |
endpoint | string | no | Submission endpoint |
category | string | yes | Compressor category |
costing | DiscoveryCostingInfo | yes | Costing strategy and rates |
maxFileSizeBytes | number | yes | Max file size for current tier |
maxConcurrentJobs | number | yes | Max concurrent jobs for current tier |
DiscoveryCostingInfo
| Field | Type | Required | Description |
|---|
strategy | string | yes | "Fixed", "PerMegabyte", "PerPage", etc. |
baseCost | number | yes | Base credit cost |
increment | number|null | no | Chunk size for PerMegabyte/PerPage (e.g. 40 = per 40 MB) |
incrementUnit | string|null | no | Unit label ("mb", "pages", "minutes") |
displaySuffix | string | yes | Human-readable cost label (e.g. "per 40 MB") |
| Field | Type | Required | Description |
|---|
job | string | yes | Job type identifier |
category | string | yes | Compressor category |
estimatedCredits | number | yes | Estimated credit cost (minimum if inputs omitted) |
costing | DiscoveryCostingInfo | yes | Costing strategy and rates |
inputs | object | yes | Input values used for the estimate |
inputs.fileSizeBytes | number|null | yes | Resolved file size in bytes |
inputs.fileSizeMb | number|null | yes | Provided MB value |
limits | object | yes | Tier-specific limits |
limits.maxFileSizeBytes | number|null | yes | Max file size for current tier |
CompressorsListResponse (legacy: GET /compress)
| Field | Type | Required | Description |
|---|
route | string | yes | Submit endpoint |
compressors | LegacyCompressorItem[] | yes | List of all available compressors |
LegacyCompressorItem
| Field | Type | Required | Description |
|---|
jobId | string | yes | Job type identifier (e.g. "image.jpg-compress") |
category | string | yes | Category ("images" or "documents") |
pool | string | yes | Worker pool name |
inputFormats | string[] | yes | Accepted input format extensions (dotted: [".jpg"]) |
outputFormats | string[] | yes | Output format extensions (dotted: [".jpg"]) |
Example (legacy):
{
"route": "/api/compress",
"compressors": [
{
"jobId": "image.jpg-compress",
"category": "images",
"pool": "ImagePool",
"inputFormats": [".jpg", ".jpeg"],
"outputFormats": [".jpg"]
}
]
}
CompareResponse (GET /compress/job/{id}/compare)
Before/after comparison data for visual quality verification.
| Field | Type | Required | Description |
|---|
beforeImage | string | yes | Base64-encoded preview of the original |
afterImage | string | yes | Base64-encoded preview of the compressed output |
originalBytes | number | yes | Original file size in bytes |
compressedBytes | number | yes | Compressed file size in bytes |
beforeMimeType | string | yes | MIME type of before preview |
afterMimeType | string | yes | MIME type of after preview |
previewWidth | number | yes | Preview image width |
previewHeight | number | yes | Preview image height |
afterPreviewWidth | number | yes | After-preview width (actual-size mode) |
afterPreviewHeight | number | yes | After-preview height (actual-size mode) |
inputWidth | number | yes | Original image width |
inputHeight | number | yes | Original image height |
outputWidth | number | yes | Compressed image width |
outputHeight | number | yes | Compressed image height |
wasResized | boolean | yes | Whether the image was resized during compression |
EntitlementsResponse (GET /compress/entitlements/me)
| Field | Type | Required | Description |
|---|
userId | string|null | no | User ID |
organizationId | string|null | no | Organization GUID |
planId | string | yes | Plan identifier |
planName | string | yes | Display name of the plan |
accessDisplayName | string|null | no | Short display label (e.g. "Pro") |
totalCredits | number | yes | Total available credits |
planCredits | number | yes | Credits from plan allocation |
loyaltyCredits | number | yes | Loyalty/bonus credits |
walletCredits | number | yes | Purchased wallet credits |
source | string | yes | Credit source ("accounts.tools.fast" or "compress.fast") |
tier | string | yes | "pro" |
Example -- Pro tier (API key authenticated):
{
"userId": "0195e2a0-1234-7000-8000-000000000099",
"organizationId": "0195e2a0-1234-7000-8000-000000000050",
"planId": "pro",
"planName": "Pro",
"accessDisplayName": "Pro",
"totalCredits": 4850,
"planCredits": 5000,
"loyaltyCredits": 0,
"walletCredits": 0,
"source": "accounts.tools.fast",
"tier": "pro"
}