curl and
Python: upload an image (one call), run a prediction, wait for it, and download
the resulting ROIs as GeoJSON, entirely over the API.
Before you start
1
Get an API key
1. Upload your image
One request does everything:POST /upload streams the file in, creates the
image record for you (named after the file), converts it, and returns the
record already ready. No pre-registration, no polling.
Each image counts against your plan’s storage cap;
POST /upload returns
402 once the cap is reached. Files can be up to 4 GB, but for anything
larger than a few hundred MB, or a connection that might drop, use the
resumable upload below.2. Pick a model and run a prediction
List the models available to your organization, then run a prediction on your image.GET /models returns shared public base models (such as Generalist)
alongside any custom models your org has trained.
3. Wait for it to finish
Segmentation runs asynchronously on GPU workers, so pollGET /predict/{prediction_id} until status is SUCCEEDED. The finished
response carries the cell_count detected.
status moves through ENQUEUED (waiting for a GPU) → STARTED (running) →
SUCCEEDED (or FAILED).
4. Export the results
Download the image’s result in whichever format you need. The overlay PNG is a presentation RGB image with masks composited over HalfPage’s normalized preview. It does not preserve original TIFF bit depth, microscopy metadata, or scientific display settings. GeoJSON is handy for GIS and web tools; the CSV is one row per cell; the ZIP is an ImageJ/FIJI ROI archive. If you predicted on one channel of a multiplex image, add that channel to the URL (?channel=2); the prediction
response carries it as channel.
Optional: share the result
To show the result to someone who doesn’t use HalfPage, get a view-only link to the image. Anyone with theurl sees the image with its latest cell outlines
and counts in their browser, no account needed. See Sharing images.
curl
Large files: the resumable upload
For multi-GB files or unreliable connections, upload the pixels straight to object storage in chunks instead of through the API. It’s the samePOST /upload endpoint. Just send JSON ({name, size})
instead of a file. No bytes travel on that request; you get back presigned part
URLs. PUT each chunk to its URL, call /complete, and poll until the image is
ready. If a chunk fails, retry that one PUT; nothing else is lost.
The presigned
PUT requests go straight to object storage, so do not send
your Authorization header on them. All other calls are authenticated with
your API key as usual.The record counts against your storage cap from the moment it is created, and
keeps counting until you delete it. If you abandon an upload,
DELETE /upload/{image_id} frees the slot: it aborts anything still in
flight and removes the record.Full Python script
segment.py: the complete workflow in one file
segment.py: the complete workflow in one file
Next steps
API reference
Every endpoint, parameter, and response, with a live playground.
Using with AI agents
Point an agent at the MCP server and OpenAPI spec to drive this flow for you.