Skip to content

Start typing to search the documentation.

↑↓to navigateto open

Reference

API Reference

REST endpoints for printers, print jobs, queues, history, materials, sites, and user provisioning, with authentication and request examples.

Use the REST API to build reporting dashboards and provision users. All paths below are relative to your deployment’s /api/rest base URL, for example https://print.example.com/api/rest. Send and receive JSON; requests with a body need Content-Type: application/json. JSON request bodies are limited to 1 MiB; file uploads use the separate slicer interface.

Jump to Printers, Jobs, Queue and history, Materials, Sites, or Users and roles.

EndpointRequired capability
GET /Any valid key
GET /printersprinters:read
GET /printers/:idprinters:read
GET /jobsjobs:read
GET /jobs/:idjobs:read
GET /jobs/:id/eventsjobs:read
GET /queue/jobsjobs:read
GET /historyjobs:read
GET /queue/estimationqueue:read
GET /queue/estimation/summaryqueue:read
GET /materialsmaterials:read
GET /materials/:idmaterials:read
GET /materials/typesmaterials:read
GET /materials/brandsmaterials:read
GET /materials/colorsmaterials:read
GET /sitessites:read
GET /sites/:idsites:read
GET /usersusers:read
GET /users/:idusers:read
POST /usersusers:write*
PUT /users/:idusers:write*
POST /users/bulkusers:write*
PUT /users/bulkusers:write*
POST /users/:id/rolesusers:write, roles:write
DELETE /users/:id/rolesusers:write, roles:write
POST /users/bulk/rolesusers:write, roles:write
PUT /users/:id/id-numberusers:write

*Including roles in a user create/update request also requires roles:write, even for an empty array or one item in a bulk request.

Authentication and access

Create a key in Admin → API Keys with the access your integration needs. See API Keys for profiles, expiration, and rotation. Every endpoint on this page requires a valid key. Send it over HTTPS in either header:

Authorization: Bearer <key>
X-API-Key: <key>

The examples use PLURAPRINT_API_KEY supplied by your secrets store or shell environment. Replace the example hostname with your deployment’s hostname:

curl --fail-with-body \
  --header "Authorization: Bearer $PLURAPRINT_API_KEY" \
  'https://print.example.com/api/rest/printers?limit=25&isEnabled=true'

A key’s capabilities apply across the deployment. siteId filters results by physical location; it does not limit what the key is authorized to read. Job access includes job names and owner IDs. Responses omit printer connection secrets, storage URLs, and raw telemetry. REST responses use Cache-Control: no-store.

CapabilityAllows
printers:readPrinter lists and details, including configured material slots
jobs:readJob lists, details, lifecycle events, queue contents, and history
queue:readQueue completion estimates
materials:readMaterial variants, types, brands, and colors
sites:readSite lists and details
users:readUser lists and details
users:writeCreate/update users and assign or clear an ID number
roles:writeRole changes, together with users:write

The Fleet reporting profile includes all five reporting capabilities. Queue reporting includes estimates only; use Read jobs and history for queue contents.

Discover endpoints

GET / · Any valid API key

Returns name, version, status, the endpoints directory, and authentication. The directory lists available routes, including routes the key may not have permission to call. Use the capability requirement documented for each endpoint.

Request and response conventions

Resource IDs for printers, jobs, materials, and sites are decimal integers from 1 to 2,147,483,647. User IDs are UUIDs. Response timestamps use ISO 8601. Nullable fields return null when the value is unavailable or unassigned.

Printer, job, event, material, and site lists accept these pagination parameters:

ParameterDefaultAccepted value
limit50Integer from 1 to 100
offset0Integer from 0 to 1000000
searchOmittedUp to 100 characters after trimming; unavailable on job events

Numeric values must be decimal integers. Boolean filters accept only true or false. Unknown query parameters and invalid values return 400. A list responds with its named collection, matching total, and pagination metadata. For example, an empty printer list:

{
  "printers": [],
  "total": 0,
  "limit": 50,
  "offset": 0,
  "hasMore": false
}

For the next page, increase offset by limit. Stop when hasMore is false. Each request reads the current data; jobs entering or leaving the queue can change later pages. User lists retain their separate pagination defaults and response shape.

Errors and retries

HTTP statusMeaningAction
400Invalid parameters, malformed body, or unknown role nameCorrect the request
401Missing, invalid, expired, revoked, or legacy keyReplace the key or fix the header
403Missing capability, or ID number identification unavailableCheck key access and deployment configuration
404Resource does not existCheck the ID
409Username, email, or ID number already assignedResolve the conflict
413JSON request body exceeds 1 MiBReduce the request size
415Unsupported request content typeSend Content-Type: application/json
429Rate limit exceededWait for Retry-After, then retry with backoff
500Server could not complete the requestRetry reads with bounded backoff; investigate repeated failures

Errors include an error string; authentication and capability errors also include a message. For example, an invalid reporting query returns:

{ "error": "Invalid query parameters" }

The API’s shared rate limit is 300 requests per minute per IP address. Integrations behind the same network address share that budget. After an uncertain write result, read the affected user before retrying. Bulk endpoints can return 207 with successful and failed items; check every result as described under Bulk results.

Printers

Both endpoints require printers:read.

List printers

GET /printers

Accepts pagination and search, plus:

ParameterFilter
siteIdExact site ID
statusoffline, idle, ready, dispatching, printing, paused, or done
modelExact catalog model identifier, such as BAMBU_LAB_P1S; unknown identifiers return 400
isEnabledtrue or false

Search matches printer names and model identifiers without case sensitivity. Results sort by printer index, then ID. Returns {printers, total, limit, offset, hasMore}.

Get a printer

GET /printers/:id

Returns a printer object, or 404 if it does not exist. No query parameters.

Printer object

List and detail responses use the same fields:

FieldType and meaning
id, index, nameResource ID, display-order integer, and printer name
notesString or null
model, status, siteIdModel identifier, printer status, and site ID
isEnabledWhether the printer is enabled
isDownWhether a current downtime record exists, including pending downtime
currentPrintJobIdCurrent job ID, or null
progressCurrent job percentage (0–100), or null without a current job
timeRemainingCurrent job’s remaining seconds, or null without a current job
lastSeenAtLast report timestamp, or null
materialsConfigured material slot assignments, ordered by extruder and slot
createdAt, updatedAtRecord timestamps

Each material assignment has slot, extruder, and material. Its material contains id, name, type: {id, name}, brand: {id, name}, and nullable color: {id, name, value}. Assignments may be manual or synchronized; they are the configured loadout rather than a guarantee of what is physically installed.

For example, GET /printers/1 might return:

{
  "id": 1,
  "index": 0,
  "name": "Workshop P1S",
  "notes": null,
  "model": "BAMBU_LAB_P1S",
  "status": "idle",
  "siteId": 1,
  "isEnabled": true,
  "isDown": false,
  "progress": null,
  "timeRemaining": null,
  "currentPrintJobId": null,
  "lastSeenAt": "2026-10-14T12:00:00.000Z",
  "materials": [],
  "createdAt": "2026-10-01T12:00:00.000Z",
  "updatedAt": "2026-10-14T12:00:00.000Z"
}

Jobs

All three endpoints require jobs:read.

List jobs

GET /jobs

Lists jobs across all lifecycle states, newest creation first. Accepts pagination and search, plus the filters below. Search matches job names, without case sensitivity.

ParameterFilter
siteIdExact job site ID; excludes jobs without an assigned site
printerIdRecorded printer assignment, current printer, or printer with an unresolved dispatch attempt
userIdJob owner UUID
statusOne job status
printerModelExact catalog model identifier, such as BAMBU_LAB_P1S; unknown identifiers return 400
createdAfterJob created at or after this ISO 8601 timestamp
createdBeforeJob created before this ISO 8601 timestamp

Timestamps must include Z or a timezone offset. The lower bound is inclusive and the upper bound is exclusive. createdBefore must be later than createdAfter when both are supplied; equal or reversed bounds return 400. These filters describe job creation time, including when used on history; they do not filter completion time.

curl --fail-with-body --get \
  --header "Authorization: Bearer $PLURAPRINT_API_KEY" \
  --data-urlencode 'createdAfter=2026-10-01T00:00:00Z' \
  --data-urlencode 'createdBefore=2026-11-01T00:00:00Z' \
  --data-urlencode 'siteId=1' \
  'https://print.example.com/api/rest/jobs'

Returns {jobs, total, limit, offset, hasMore}. Creation time ties are resolved by job ID.

Get a job

GET /jobs/:id

Returns a job object, or 404 if it does not exist. No query parameters.

Job object

Job lists, details, queue contents, and history use the same fields:

FieldType and meaning
id, name, statusJob ID, name, and lifecycle status
siteId, userIdSite ID and owner UUID; each may be null
printerModelTarget model identifier, or null before definition
printerId, currentPrinterIdRecorded printer assignment and current printer ID; each may be null
dispatchAttemptPrinterId, hasUnresolvedDispatchPrinter ID for an unresolved dispatch attempt (null if none), and whether such an attempt exists
progress, timeRemainingStored progress percentage (0–100) and remaining seconds
priority, deadlineInteger priority and optional deadline timestamp (null when unset)
isReprintWhether this job was created as a reprint
approvedAtApproval timestamp, or null
estimatedDurationSecondsEstimated print duration, or null when unknown
quantitiesMaterial estimates with explicit units, or null when unknown
materialRequirementsArray of required materials, ordered by extruder and material index
createdAt, updatedAtRecord timestamps

Stored progress and remaining time may be zero before printing; use status to determine the job’s lifecycle state. Each material requirement contains index, extruder, type: {id, name}, nullable brand: {id, name}, and nullable color: {id, name, value}. A null brand or color leaves that attribute unspecified. When hasUnresolvedDispatch is true, printing may already have started without confirmation. Do not infer failure or submit a duplicate job from missing confirmation.

quantities contains version: 1, total, and perMaterial. Quantity objects can contain massG (grams), volumeMl (millilitres), and lengthMm (millimetres). Missing values mean unknown, not zero. perMaterial also includes each material’s index. Optional derived arrays name quantities calculated from another unit. For example:

{
  "version": 1,
  "total": { "massG": 24.5 },
  "perMaterial": [{ "index": 0, "massG": 24.5 }]
}

A job response can look like this; IDs and names here are illustrative:

{
  "id": 42,
  "name": "Mounting bracket",
  "status": "printing",
  "siteId": 1,
  "userId": "550e8400-e29b-41d4-a716-446655440000",
  "printerModel": "BAMBU_LAB_P1S",
  "printerId": 1,
  "currentPrinterId": 1,
  "dispatchAttemptPrinterId": null,
  "hasUnresolvedDispatch": false,
  "progress": 40,
  "timeRemaining": 900,
  "priority": 0,
  "deadline": null,
  "isReprint": false,
  "approvedAt": "2026-10-14T11:40:00.000Z",
  "estimatedDurationSeconds": 1500,
  "quantities": {
    "version": 1,
    "total": { "massG": 24.5 },
    "perMaterial": [{ "index": 0, "massG": 24.5 }]
  },
  "materialRequirements": [
    { "index": 0, "extruder": 0, "type": { "id": 1, "name": "PLA" }, "brand": null, "color": null }
  ],
  "createdAt": "2026-10-14T11:30:00.000Z",
  "updatedAt": "2026-10-14T12:00:00.000Z"
}

Get job events

GET /jobs/:id/events

Returns the job’s lifecycle event records as {events, total, limit, offset, hasMore}. Accepts limit and offset; no search or job filters. Events sort oldest first, then by ID. A missing job returns 404; an existing job with no events returns an empty list. Each event contains id, printJobId, type, nullable userId, and createdAt. Raw event details and user profiles are excluded.

Event types are uploaded, processing, awaiting_approval, approved, rejected, queued, dispatching, started, progress, completed, failed, cancelled, reprinted, prioritized, deprioritized, and revision_requested. Event types and job statuses describe different things; for example, the started event accompanies printing.

Job statuses

GroupStatus values
Intake and preparationuploaded, draft, pending_file, processing, pending_definition, awaiting_approval
Waiting and activequeued, dispatching, printing, paused
Terminalcompleted, failed, rejected, cancelled, expired

uploaded is a legacy intake state. See Submitting a Print Job for the preparation and approval process.

Queue and history

List queue jobs

GET /queue/jobs · jobs:read

Lists every nonterminal job, including intake and preparation. Accepts the same pagination and job filters as /jobs, but status must be nonterminal; a terminal status returns 400. Returns {jobs, total, limit, offset, hasMore} with the same job shape as /jobs.

Results place active jobs first, then queued jobs by priority and first-in-first-out order, then intake and preparation jobs. This is a listing order; it does not promise dispatch order or a per-job start time. Printer compatibility and policies still determine dispatch.

List history

GET /history · jobs:read

Lists completed, failed, rejected, cancelled, and expired jobs, newest creation first. Accepts the same pagination and job filters as /jobs, but status must be terminal; a nonterminal status returns 400. Returns {jobs, total, limit, offset, hasMore}. Each row is a job, rather than an individual print attempt or event.

Estimate queue completion

GET /queue/estimation · queue:read

Returns the estimated time to finish queued and active work across the deployment. The only query parameter is refresh: true bypasses the 30-second estimate cache; false or omission uses the cache when available. Other values return 400.

Response fieldMeaning
totalSeconds, formattedTimeEstimated remaining completion horizon, in seconds and a display string
hasUnknownWaitSome work has an unknown wait; totalSeconds is a lower bound
queuedJobCount, activeJobCount, totalJobCountQueued, active, and combined counts
activePrinterCountPrinters included in the estimate
calculatedAtCalculation timestamp
breakdownPer-model estimates and counts
printingJobCountDeprecated alias for activeJobCount

Each breakdown row includes printerModel, totalSeconds, formattedTime, hasUnknownWait, queuedJobCount, activeJobCount, totalJobCount, printerCount, and averageTimePerJob (rounded seconds). jobCount is a deprecated alias for totalJobCount. Active work includes dispatching, printing, and paused jobs. Estimates depend on compatible printers, availability, materials, and policy; they are not guaranteed finish times.

Get an estimate summary

GET /queue/estimation/summary · queue:read

Returns only totalSeconds, formattedTime, and hasUnknownWait, using the estimate cache. No query parameters. For an empty queue with no uncertain work:

{ "totalSeconds": 0, "formattedTime": "0m", "hasUnknownWait": false }

Materials

All five endpoints require materials:read. Materials are the configured catalog of filaments and resins. These endpoints do not report remaining spool mass or resin volume. All material lists sort by name, then ID. Name searches are case-insensitive; matching tags and alternate names uses exact values.

List material variants

GET /materials

Accepts pagination and search, plus optional form=filament or form=resin. A variant combines a type, brand, and optional color. Search covers variant, type, brand, and color names, their tags, and type alternate names. Returns {materials, total, limit, offset, hasMore}.

Get a material variant

GET /materials/:id

Returns a material variant object, or 404 if it does not exist. No query parameters.

Material variant object

Variants contain id, name, tags, createdAt, updatedAt, and:

FieldContents
typeid, name, form, alternateNames, tags, createdAt, updatedAt
brandid, name
colorid, name, value, or null

form is filament or resin. Color value is the catalog’s color value string.

An example GET /materials/1 response:

{
  "id": 1,
  "name": "Workshop PLA",
  "tags": [],
  "type": {
    "id": 1,
    "name": "PLA",
    "form": "filament",
    "alternateNames": [],
    "tags": [],
    "createdAt": "2026-10-01T12:00:00.000Z",
    "updatedAt": "2026-10-01T12:00:00.000Z"
  },
  "brand": { "id": 1, "name": "Workshop materials" },
  "color": null,
  "createdAt": "2026-10-01T12:00:00.000Z",
  "updatedAt": "2026-10-01T12:00:00.000Z"
}

List material types

GET /materials/types

Accepts pagination and search, plus optional form=filament or form=resin. Search covers names, alternate names, and tags. Returns {types, total, limit, offset, hasMore}. Each type contains id, name, form, alternateNames, tags, createdAt, and updatedAt.

List material brands

GET /materials/brands

Accepts pagination and search; search covers names and tags. Returns {brands, total, limit, offset, hasMore}. Each brand contains id, name, tags, createdAt, and updatedAt.

List material colors

GET /materials/colors

Accepts pagination and search; search covers names and tags. Returns {colors, total, limit, offset, hasMore}. Each color contains id, name, value, tags, createdAt, and updatedAt.

Sites

Both endpoints require sites:read. Sites group printers and agents by location or network; access remains deployment-wide.

List sites

GET /sites

Accepts pagination and search; search matches site names without case sensitivity. Results sort by name, then ID. Returns {sites, total, limit, offset, hasMore}.

Get a site

GET /sites/:id

Returns a site object, or 404 if it does not exist. No query parameters. Site objects contain id, name, description, nullable disabledAt, createdAt, and updatedAt. Disabled sites remain in the list. An example site response:

{
  "id": 1,
  "name": "Main lab",
  "description": "Printers in the main lab",
  "disabledAt": null,
  "createdAt": "2026-10-01T12:00:00.000Z",
  "updatedAt": "2026-10-01T12:00:00.000Z"
}

Users and roles

User responses contain id, username, displayName, nullable email, roles (role names), createdAt, and updatedAt. User IDs are UUIDs; role inputs use existing role names, including capitalization. Unknown role names return 400.

List users

GET /users · users:read

Accepts limit (default 100, maximum 1000), offset (default 0), and optional search. Search matches display names, usernames, and email addresses without case sensitivity. Results sort by display name. Returns {users, total, limit, offset}. This endpoint does not include hasMore; compare offset + users.length with total.

Get a user

GET /users/:id · users:read

Returns a user object, or 404 if it does not exist.

Create a user

POST /users · users:write, plus roles:write when roles is present

Required body fields: username, displayName, email. Optional: roles (array of existing role names). Returns 201 with the created user. An existing username or email returns 409. Creating a user does not set a password.

{
  "username": "alex",
  "displayName": "Alex Morgan",
  "email": "alex@example.com"
}

Update a user

PUT /users/:id · users:write, plus roles:write when roles is present

The body accepts username, displayName, email, and roles; all fields are optional. Omitted fields retain their values. roles replaces all role assignments; [] removes all roles. Returns 200 with the updated user, 404 for a missing user, or 409 for a username or email conflict.

{ "displayName": "Alex Rivera" }

Create users in bulk

POST /users/bulk · users:write, plus roles:write if any item includes roles

Body: { "users": [...] }, with 1–100 user objects using the same fields as Create a user. Required fields and role names are checked before any users are created. Returns 201 if every creation succeeds, otherwise 207 with bulk results.

Update users in bulk

PUT /users/bulk · users:write, plus roles:write if any item includes roles

Body: { "users": [...] }, with 1–100 objects. Each requires id and accepts the optional fields from Update a user. Role names are checked before updates begin. Returns 200 if every update succeeds, otherwise 207 with bulk results.

{
  "users": [
    { "id": "550e8400-e29b-41d4-a716-446655440000", "displayName": "Alex Rivera" }
  ]
}

Assign roles

POST /users/:id/roles · users:write and roles:write

Body: { "roles": ["Member"] }. Adds the named roles, preserving existing assignments and avoiding duplicates. Returns 200 with the updated user; a missing user returns 404. Use a role name configured in your deployment.

Remove roles

DELETE /users/:id/roles · users:write and roles:write

Send a JSON body: { "roles": ["Member"] }. Removes only those roles, preserving other assignments. Returns 200 with the updated user; a missing user returns 404.

Assign roles in bulk

POST /users/bulk/roles · users:write and roles:write

Body: { "assignments": [...] }, with 1–100 objects containing userId and a roles array. Adds roles as in Assign roles. Role names are checked before assignments begin. Returns 200 if all succeed, otherwise 207 with bulk results.

{
  "assignments": [
    { "userId": "550e8400-e29b-41d4-a716-446655440000", "roles": ["Member"] }
  ]
}

Assign or clear an ID number

PUT /users/:id/id-number · users:write

Requires ID number identification to be enabled and configured. Body: idNumber as a string of 1–32 digits, or null to clear it. Leading zeros are preserved. Returns { "success": true }; it does not return the number. A number assigned to another user returns 409 and leaves the current assignment intact. An unavailable identification method returns 403.

{ "idNumber": "00123456" }
{ "idNumber": null }

Bulk results

Bulk writes are processed item by item after initial validation. Successful changes remain applied when another item fails. The response contains results and a summary with total, succeeded, and failed. index is the zero-based position in the request array. Treat 207 as a signal to inspect every result, including when all items failed.

OperationSuccessful resultFailed result
Create userssuccess, index, usersuccess: false, index, error
Update userssuccess, index, id, usersuccess: false, index, id, error
Assign rolessuccess, index, userId, rolessuccess: false, index, userId, error

Bulk user objects contain id, username, displayName, nullable email, and roles; they omit timestamps. Retry only failed items after resolving their errors. Replaying an entire create batch would conflict with users already created.

Slicer uploads

Slicer uploads use the separate OctoPrint-compatible interface at /api/ingest/octoprint, with /api/ingest/orca-3mf retained for existing slicer profiles. API keys need files:upload, and the issuing person must still have upload permission. This capability does not grant access to the reporting or user endpoints above.

GET /api/ingest/octoprint/api/version tests the connection. POST /api/ingest/octoprint/api/files/local accepts one multipart file, up to 1 GB. Uploads create work for preparation and approval; print=true does not start printing. See Submitting a Print Job.

Last updated