Formlabs Developers
Download PreForm Insider to start developing with the PreForm API.
Version v1.0.0-alpha (latest)

PreForm API

v1.0.0-alpha OpenAPI 3.1.0

The PreForm API prepares jobs for Formlabs printers and sends them to print. PreForm, or PreForm Server, its windowless edition, serves it over HTTP on your own machine.

From a script or a pipeline, import models; orient, support and lay them out; check printability; and slice or print the result. It supports Formlabs SLA and SLS printers; /v1/print-setting/list/ lists every printer and material a server supports.

Every v1 endpoint is under /v1/.

Base URL

http://localhost:44388

PreForm or PreForm Server on the local machine, on the port it was started with: PreForm Server's required --port argument, or the port chosen when starting the server from PreForm's File menu.

Just getting started?

How PreForm Server differs from a cloud API#

Most web APIs, such as the Formlabs Web API, are stateless REST services: each request stands alone, and resources live in the provider's database. PreForm Server is a desktop application with an HTTP interface. It holds your work in memory between requests and runs beside your files and printers.

  1. State lives in the server process. Scenes, models, operations and the Dashboard login live in the server's memory and vanish when it exits. Save work with /v1/scene/save/ and reopen it with /v1/scene/open/. Create or open a scene first; endpoints that act on it take its scene_id.
  2. Endpoints are actions, not resources. Each route names an action, such as /v1/scene/model/auto-orient/, and takes a JSON body, so most are POST, reads included. A response reports what the action did, such as the ids it created or work it left unfinished, not the resulting state. Read state with /v1/scene/get/ or /v1/scene/model/list/.
  3. Changes to a scene run in order. Requests that change a scene run one at a time, in arrival order, and each sees the results of those before it. Reads don't wait: they return the scene as the last finished request left it.
  4. It runs on your machine. The server listens on localhost and has no API keys: whatever reaches the port can use it, so keep the port private to the machine. File paths in requests refer to the server's machine, or to its container when it runs in Docker. Endpoints that call Formlabs web services also need a Dashboard login (/v1/login/), and say so in their descriptions.
Architecture
Your code Python SDK, or any HTTP client HTTP ยท localhost:44388 PreForm Server one process, on your machine Scenesmodels, settings Operationsasync progress Held in memory: gone when the process exits Files on this machine.stl .step .form .fps PrintersLAN, Fleet Control Formlabs Dashboardlogin, cloud slicing

A typical session#

Work follows the server's lifetime. Start the server or connect to one that is running, create a scene, and change it one request at a time. Each request builds on the state the last one left.

Save the scene to a .form file before the server exits; the scene goes with it.

A session
Python
from formlabs_sdk import FormlabsClient

with FormlabsClient() as client:
    # Attach to PreForm, or PreForm Server, on port 44388.
    preform = client.preform.connect()

    # The scene lives in the server's memory...
    scene = preform.create_scene(
        machine_type="FORM-4-0",
        material_code="FLGPGR05",
        layer_thickness_mm=0.1,
    )
    sid = scene.scene_id
    preform.import_models(scene_id=sid, file="part.stl")
    preform.auto_orient_models(scene_id=sid)

    # ...so save it to keep it once the server exits.
    preform.save_form_file(
        scene_ids=[sid], file="part.form"
    )
Terminal
curl -X POST "http://localhost:44388/v1/scene/create/" \
  -H "Content-Type: application/json" \
  -d '{
    "machine_type": "FORM-4-0",
    "material_code": "FLGPGR05",
    "layer_thickness_mm": 0.1
  }'
# {"scene_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", ...}

curl -X POST "http://localhost:44388/v1/scene/model/import/" \
  -H "Content-Type: application/json" \
  -d '{
    "scene_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "file": "C:\\Models\\part.stl"
  }'

curl -X POST "http://localhost:44388/v1/scene/model/auto-orient/" \
  -H "Content-Type: application/json" \
  -d '{
    "scene_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  }'

# Write the scene to disk: it is lost when the server exits.
curl -X POST "http://localhost:44388/v1/scene/save/" \
  -H "Content-Type: application/json" \
  -d '{
    "scene_ids": [
      "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    ],
    "file": "C:\\Models\\part.form"
  }'

Asynchronous requests#

Slicing, importing a large CAD file and generating supports can take minutes. Endpoints that can run long accept ?async=true and return 202 Accepted at once, with an operation_id and an operation_url (also in the Location header).

Poll the operation_url until status is SUCCEEDED or FAILED; result then holds the response the endpoint would have returned synchronously. Like scenes, operations do not survive a restart.

Without async, a call blocks until it finishes or reaches the server's 10-minute timeout.

Asynchronous request
Python
from formlabs_sdk import FormlabsClient

with FormlabsClient() as client:
    preform = client.preform.connect()

    # The SDK sends ?async=true and polls for you.
    result = preform.import_models(
        scene_id="3fa85f64-5717-4562-b3fc-2c963f66afa6",
        file="assembly.step",
        on_progress=lambda p: print(f"{p:.0%}"),
        timeout=600,
    )
Terminal
curl -X POST "http://localhost:44388/v1/scene/model/import/?async=true" \
  -H "Content-Type: application/json" \
  -d '{
    "scene_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "file": "C:\\Models\\assembly.step"
  }'

# Poll the operation_url until status is SUCCEEDED or FAILED.
curl "http://localhost:44388/v1/operation/get/?operation_id=7c9e6679-7425-40de-944b-e07fc1f90ae7"
Response
JSON
{
  "operation_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "operation_url": "/v1/operation/get/?operation_id=7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "message": "Operation accepted. Poll GET /v1/operation/get/?operation_id=7c9e6679-7425-40de-944b-e07fc1f90ae7"
}
JSON
{
  "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "status": "SUCCEEDED",
  "progress": 1.0,
  "result": {
    "new_models": [{ "model_id": "c2a37eb2-8e4b-4b8e-9f37-1f5f2c1a9d10" }]
  }
}

Errors#

The API uses conventional HTTP status codes, and every error body is an error object with a code and a message.

Program against code, never against message. Codes are stable SCREAMING_SNAKE_CASE identifiers from the ErrorCode registry; new ones may appear without a version change, so handle codes you don't recognize. Messages are for people and may change in any release.

Each endpoint's Error codes table lists the codes it returns and their causes.

Error response
Python
from formlabs_sdk import FormlabsClient, PreFormApiError

with FormlabsClient() as client:
    preform = client.preform.connect()
    sid = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    try:
        scene = preform.get_scene(scene_id=sid)
    except PreFormApiError as error:
        # Match on the code, never on the message.
        if error.code != "INPUT_ERROR":
            raise
        print("No such scene")
JSON
{
  "error": {
    "code": "INPUT_ERROR",
    "message": "Scene with given scene_id not found"
  }
}
HTTP status codes
StatusMeaning
200 OKThe request succeeded.
202 AcceptedStarted with ?async=true. Poll the returned operation.
400 Bad RequestThe request was malformed or referenced something that does not exist.
404 Not FoundA referenced resource, such as a model or a connected printer, does not exist, or the path is not a v1 endpoint. The code is NOT_FOUND.
409 ConflictThe server's current state prevents the request: a referenced resource is busy with another operation, or the request needs more scenes than the server can hold.
422 Unprocessable EntityThe request is well-formed and names a real scene, but the scene's current configuration does not support it.
500 Internal Server ErrorSomething failed inside the server that the request did not cause.

Conventions#

Identifiers#

Scenes, models and operations have UUIDs. Responses give them bare (3fa85f64-5717-4562-b3fc-2c963f66afa6); requests also accept the braced form ({3fa85f64-...}).

Enums#

Enum values are SCREAMING_SNAKE_CASE. Request enums are closed: a value outside the list fails with 400 JSON_SCHEMA_MATCH_ERROR. Later releases may accept new values, which older servers reject the same way. Response enums are open: schemas that list their values under x-extensible-enum, instead of enum, may gain values in any release without a version change, so treat an unrecognized value as unknown instead of failing.

Created models#

Requests that add models return their ids, in no particular order. When they derive from an existing model (copies, split bodies, a drilled plug), the response names it too, so you never need to diff the scene.

Enum in a response
JSON
{
  "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "status": "IN_PROGRESS",
  "progress": 0.42
}

Resources#

Server Info

Endpoint for checking that the server is up and reachable.

1 endpoint

Authentication

Endpoints for checking and managing your Formlabs Dashboard account login state. Endpoints that call Formlabs web services need a login session, and say so in their descriptions.

3 endpoints

Scenes

Create, load, and enumerate scenes. A scene is the top-level unit of work: it holds a printer/material/print-setting combination and the models placed within that printer's build volume.

12 endpoints

Modifying Models

Endpoints that take actions on models within a scene.

24 endpoints

Printability Checks

Scene printability checks. These endpoints analyze the scene and report problems. They never modify it.

7 endpoints

Print Settings

The catalog of machine/material/layer-thickness/print-setting combinations Formlabs ships settings for, and validation of a candidate combination against that catalog.

3 endpoints

Operations

Poll and manage the long-running operations started by endpoints called with ?async=true. /v1/operation/get/ returns one operation's status and, once finished, its result. See the Asynchronous requests section of the introduction.

3 endpoints

Devices

Enumerate printers and Fleet Control printer groups PreForm knows about, discover new ones on the network, and upload firmware to them. Discovering Dashboard-registered printers and Fleet Control queues requires a Dashboard login (/v1/login/).

3 endpoints

Errors

The shared error envelope and the registry of stable error codes. See the Errors section of the introduction for the contract.

Reference

Schemas

The 135 request and response schemas.

Download the OpenAPI specification

Feedback & Bug Reports