API
All endpoints are served over HTTP. Requests and responses use JSON (Content-Type: application/json) unless noted otherwise.
Health check
GET /health
Returns 200 OK with an empty body. Used by load balancers and orchestrators to verify the service is running.
Jobs
POST /jobs
Creates a new print job and publishes it to RabbitMQ.
Request body
{
"photos": [
{ "photoStorageKey": "stand-1-abc123.jpg", "copies": 2 },
{ "photoStorageKey": "stand-1-def456.jpg", "copies": 1 }
]
}
| Field | Type | Required | Description |
|---|---|---|---|
photos | array | yes | List of photos to print. At least one required. |
photos[].photoStorageKey | string | yes | Object key in MinIO (e.g. stand-1-abc123.jpg) |
photos[].copies | int | yes | Number of copies to print. Must be >= 1. |
Response 201 Created
{
"jobId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"status": "queued",
"createdAt": "2026-04-13T10:00:00Z"
}
Response 400 Bad Request
Returned when the photos array is empty.
GET /jobs
Returns a paginated list of jobs, optionally filtered by status.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
status | string | (all) | Comma-separated list of statuses to filter by. Accepted values: queued, printing, requeued, done, error. |
limit | int | 50 | Maximum number of jobs to return. |
offset | int | 0 | Number of jobs to skip. |
sort | string | (none) | Set to status to order by status priority: printing first, then requeued, queued, error, done. |
Response 200 OK
{
"jobs": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"status": "printing",
"total": 3,
"printed": 1,
"retryCount": 0,
"createdAt": "2026-04-13T10:00:00Z",
"updatedAt": "2026-04-13T10:00:05Z"
}
],
"total": 42
}
| Field | Description |
|---|---|
jobs | Array of job summaries for the current page |
total | Total number of jobs matching the filter (before pagination) |
id | Job UUID |
status | Current status: queued, printing, requeued, done, or error |
total (job) | Total number of photos in the job |
printed | Number of photos printed so far |
retryCount | Number of times the job has been requeued by the watchdog |
GET /jobs/{jobId}
Returns full details for a single job, including the list of photos.
Path parameter
| Parameter | Type | Description |
|---|---|---|
jobId | UUID | Job identifier |
Response 200 OK
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"status": "done",
"total": 2,
"printed": 2,
"retryCount": 0,
"createdAt": "2026-04-13T10:00:00Z",
"updatedAt": "2026-04-13T10:01:00Z",
"photos": [
{ "photoStorageKey": "stand-1-abc123.jpg", "copies": 2 },
{ "photoStorageKey": "stand-1-def456.jpg", "copies": 1 }
]
}
Response 404 Not Found
Returned when no job exists with the given jobId.
GET /jobs/{jobId}/stream
Streams job status updates using Server-Sent Events (SSE).
Path parameter
| Parameter | Type | Description |
|---|---|---|
jobId | UUID | Job identifier |
Response headers
Content-Type: text/event-stream
Cache-Control: no-cache
X-Accel-Buffering: no
Event format
Each event is a data: line followed by a blank line:
data: {"jobId":"3fa85f64...","status":"printing","printed":1,"total":3,"error":null}
data: {"jobId":"3fa85f64...","status":"done","printed":3,"total":3,"error":null}
| Field | Description |
|---|---|
jobId | Job UUID as a string |
status | Current status |
printed | Photos printed so far |
total | Total photos in the job |
error | Error message if status is error, otherwise null |
The first event is sent immediately with the current job state. The connection closes automatically once status is done or error. The client can reconnect at any time and will receive the current state on connect.
Response 404 Not Found
Returned when no job exists with the given jobId.
Photos
GET /photos
Returns a paginated list of photos available in MinIO, with pre-signed URLs.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | int | 50 | Maximum number of photos to return. |
offset | int | 0 | Number of photos to skip. |
Photos are listed from the low/ prefix in the configured MinIO bucket and sorted lexicographically by key before pagination.
Response 200 OK
{
"photos": [
{
"key": "low/stand-1-abc123.jpg",
"url": "https://minio.example.com/photostand/low/stand-1-abc123.jpg?X-Amz-..."
}
],
"total": 120
}
| Field | Description |
|---|---|
photos | Array of photo entries for the current page |
photos[].key | Object key in MinIO |
photos[].url | Pre-signed URL valid for 1 hour |
total | Total number of photos in the bucket (before pagination) |