-

Please Enter Your Search
search icon
Nothing found for your search
Search results from other manuals
Nothing found for your search

1 Endpoint reference

Every endpoint a user or admin account can reach, in one place. This is a lookup chapter rather than a tutorial: the tables give the shape of each call and the one thing about it that catches people out. The chapters before this one explain why you would make the call at all.

1.1 Conventions

Every path in the tables is relative to /api. GET /init means GET https://<device>/api/init. The prefix is left out to keep the columns narrow.

Authentication is a session cookie. POST /login sets session=<uuid>; send it on everything else. A missing cookie is 400 with code 2-1-4, and an expired or unknown one is 400 with 2-1-2. Nothing in this API answers 401, so a client that watches for 401 will never re-authenticate. An account that lacks the rights for a route gets 403 and 2-1-5.

The Role column reads: any for both user and admin, admin for admin only, none for endpoints that work without a session at all.

Any request that carries a body must send Content-Type: application/json. Without it the request never reaches the endpoint; you get 415 and an error that does not mention the header you forgot. Requests without a body do not need the header.

Errors are double-encoded. The body is an object whose error field holds another JSON document as a string:

{"error": "{\"code\": \"2-11-12\", \"message\": \"The sequence needs to be at least 8 bases long!\"}"}

Parse twice, and branch on code. A few responses put a plain string in error instead; see the error codes chapter.

Listings are paged. GET /processRuns and GET /processRuns/queue accept from and limit as query parameters and default to limit=15. A limit below 1 or a negative from is an error, not a clamp.

Ids are opaque strings such as 2026-08-09T22:05:25Z-0be17442. They look like timestamps and are not: do not parse, sort or construct them. They contain colons, so URL-encode them if your HTTP library does not.

Timestamps are RFC 3339, durations are integer milliseconds. duration: 5400000 is ninety minutes.

1.2 Session endpoints

Endpoint Role Body Returns Notes
POST /login none {"username", "password"} session object username is the account id, not the display name
PUT /logout any none empty Optional, but a reconnecting service should call it

1.3 Device state endpoints

Endpoint Role Body Returns Notes
GET /init any or none none snapshot object Without a cookie you get only status, not an error
GET /status any or none none machine status Unauthenticated it returns two fields
GET /subscribe any none text/event-stream Sends no CORS headers; open it from a backend

GET /init is the batch snapshot and the right way to start. For a user or admin session its top-level keys are exactly ccSettings, errors, kbDevMode, processRunQueue, processRuns, sensorState, session, settingsUser and status. Without a session the whole body is {"status": {"deviceName": ..., "serverTime": ...}}, which is also what GET /status gives you unauthenticated — enough for a health check and nothing more.

processRunQueue in that snapshot is the queue in the order the machine plans to run it. GET /processRuns/queue returns storage order, so prefer /init when order matters.

1.4 Queue endpoints

Endpoint Role Body Returns Notes
POST /processRuns/queue any ProcessRun template your request echoed The reply has no id; re-read the queue
GET /processRuns/queue any none ProcessRun array Storage order, not queue order
GET /processRuns/queue/:id any none ProcessRun Queued entries only; a started run is not here
PUT /processRuns/queue/:id any complete ProcessRun updated entry Fields you omit are cleared, not kept
DELETE /processRuns/queue/:id any none empty Cannot remove a run that already started
POST /processRuns/queueImportBrowser any {"content", "processRun"} concatenated objects The reply is not valid JSON; re-read the queue

The echo from POST /processRuns/queue is your request, not the stored entry: it carries no id, no processIds and no duration. Read the queue afterwards and diff against the ids you had before. That read-back is also the only confirmation that the machine could plan the run at all.

POST /processRuns/queueImportBrowser takes a whole FASTA file in content and one template in processRun, and queues one entry per record with the header line as its title. One cartridge and chip pair applies to the entire file. The response body is a series of JSON objects written one after another with no enclosing array, so most parsers will read the first and stop or fail; ignore it.

priority is a sort key, not an address. After any change the machine renumbers the whole queue from 1, so the number you set is not the number you will read back.

1.5 Run endpoints

Endpoint Role Body Returns Notes
POST /processRuns any {"id": "<queue entry id>"} started ProcessRun Only the first entry in the queue may start
GET /processRuns any none ProcessRun array Paged at 15; pass from to walk backwards
GET /processRuns/:id any none ProcessRun Started runs only; queued ids give 404
PUT /processRuns/:id any ProcessRun updated run Applies title and metadata and nothing else
PUT /processRuns/:id/control any {"answers": {...}} updated run Answer values are strings, never booleans

Starting is the fussiest call in the API. The body only needs the id of a queue entry; everything else in it is ignored. If that entry is not at the front of the queue you get 1-1-9, and if anything is already running you get 1-1-8. To run something sooner, move it to the front with PUT /processRuns/queue/:id and start again.

PUT /processRuns/:id/control answers the machine's checkpoint questions. The keys are answer ids taken from pendingAnswers in the status, and confirmations must be the literal string "true" — a JSON boolean is rejected, and "false" on a confirmation is rejected as well. Send one answer at a time and wait for it to leave pendingAnswers before sending the next.

1.6 Cancel endpoints

Endpoint Role Body Returns Notes
GET /control/cancel any none machine status Takes the lease and stops the machine immediately
PUT /control/cancel/confirm any none machine status A recovery run follows; the run is not over yet
PUT /control/cancel/abort any none machine status Releases the lease and lets the run continue

Canceling is deliberately two calls. The first takes a lease: the machine goes to emergencyStop at once and the returned status carries cancelLeaseExpiresAt, which every connected client can see. The lease runs for five minutes. The second call either commits the cancel or releases it.

All three refuse with 1-1-17 while any error is active, which is the opposite of what you would expect, since an error is often exactly when you want to stop. Clear the error first with PUT /errors/handle/:id.

1.7 Error endpoints

Endpoint Role Body Returns Notes
PUT /errors/handle/:id any {"cancelRun", "error"} the stored error The echo still says active: true; re-read instead
POST /startEmergencyRun none none ProcessRun Only valid in sensor emergency; otherwise 1-2-15
PUT /resetEmergencyMode none none empty Resets sensor counters, not the active errors

cancelRun decides the fate of whatever was running: true abandons it, false acknowledges the error and leaves the run in place. error is the error object you read from /init or the errors event, sent back whole. An unknown error id answers 404 with the plain string form of the error envelope rather than the usual double-encoded one.

The two emergency endpoints need no session, so a person at a locked-out machine can recover it. They are not a general stop button: startEmergencyRun only works when the machine has already put itself into a sensor emergency state.

1.8 Settings endpoints

Endpoint Role Body Returns Notes
GET /settingsUser/systemInformation any none system information Cheapest check that you are connected and authenticated
PUT /settingsUser/systemInformation any system information stored object Only localization and timezone, unless userCommand is set
GET /settingsUser/oligoYield any none yield settings Display figures only; synthesis ignores them
PUT /settingsUser/oligoYield any {"resuspensionVolume", "oligoYield"} stored object Replaces both values every time
GET /settingsUser/security admin none security settings remoteAccess is read from disk, not stored here
PUT /settingsUser/security admin security settings current settings factoryReset: true erases the device
GET /usbFiles admin none file tree Fails with 2-14-16 when no stick is inserted
POST /settingsUser/sslFiles admin SSL file paths your request echoed Restarts the listener; your connection drops
POST /settingsUser/wifiScan admin {"enableWifiScan"} empty Starts a scan; results arrive on another call
POST /settingsUser/getWifiConfig admin network request network request A read, despite being a POST with a body
PUT /settingsUser/networkRequest admin network request your request echoed Changing the address can cut you off mid-call
GET /settingsUser/networkResponse admin none network settings Live state, not what you last asked for

GET /settingsUser/systemInformation is worth knowing well: it carries serialNr, softwareVersion, firmwareVersion, userTimezone, systemTime, and the recommendedCartridgeType and recommendedChipKind this device was configured for. Quote the serial number and software version in any support request.

PUT /settingsUser/systemInformation normally stores only localization and userTimezone. Setting userCommand to changeSystemTime makes it a clock change instead, and then setTime must be formatted 2006-01-02 15:04:05 exactly.

1.9 Account endpoints

Endpoint Role Body Returns Notes
GET /users admin none user array Password hashes are blanked; dev is hidden
POST /users admin complete user array the array back Every account you leave out is deleted
POST /changeAccount/:id any {"PWDNew", "PWDConfirm"} blanked echo Your own id only; anything else gives 2-16-10
POST /confirmPWD/:id admin {"username", "password"} empty Checks a password and changes nothing

POST /users is a whole-collection replace, not a create. Read GET /users, modify the array, and post all of it back. An account missing from the array you send is deleted, so a client that posts one new user wipes every other account. Leave password empty on an existing account to keep the current one; a non-empty password is hashed and replaces it. Accounts with the dev role cannot be created and are never deleted this way.

Ordinary users change their own password through POST /changeAccount/:id, where :id is their own account id. An admin cannot use it to change somebody else's.

1.10 Object fields

ProcessRun

One entry in the queue, and the same object once it has started. On a queue POST the machine keeps only the fields marked below and rebuilds everything else from its own state, so there is no point sending more.

Field Type Set by client Meaning
id string no Opaque identifier, assigned when the entry is stored
createdAt timestamp no When the entry was created
updatedAt timestamp no Last modification
title string yes Free text. Defaults to a generated name such as Oligo 2026-08-09.3
processType string yes synthesis for an oligo. Other values drive machine operations such as manualCleaning
cartridgeType string yes Numeric string. 2 is the standard cartridge, 3 the 6-FAM one
chipKind string yes Chip identifier. 2 is the standard chip, 3-BHQ1 the dual-labeled one
priority number yes Position in the queue. Renumbered from 1 after every change
answers object sequence only On a queue POST, only answers.sequence is meaningful. Later answers go through the control endpoint
metadata array on started runs Free-form labels. See below
processIds array no The processes the machine planned to reach your run
processTypes array no One entry per planned process, in order
cartridgeId string no The cartridge that was in the machine when the run was planned or started
cartridgeExpiresAt timestamp no Expiry of that cartridge
totalBasesCountBefore number no Bases left on the cartridge before this run
duration number no Estimated total, in milliseconds
durations array no Estimate per planned process, in milliseconds
startedAt timestamp no When the run left the queue
finishedAt timestamp no While running this is the projected end, not a fact. It becomes the real time when the run ends
abortedAt timestamp no Set instead of finishedAt when a run is canceled
isContinuedRun boolean no The run followed straight on from another
isCanceling boolean no A cancel is in progress for this run

PUT /processRuns/queue/:id accepts title, metadata, answers, cartridgeType, chipKind and priority, and overwrites each of them with what you send — including with nothing. PUT /processRuns/:id, on a run that has already started, applies title and metadata only.

Metadata

A list of small labeled values carried with a run, seeded from a device-wide default list. Use it to write your own order number or sample id onto a run.

Field Type Set by client Meaning
id string yes Your key for the entry
name string yes Label shown at the Kilobaser
type string yes Free text describing the kind of value
data string yes The value itself, always a string
unit string yes Optional unit

Metadata written to a queued entry does not survive. The machine rebuilds queue entries whenever anything in the queue changes, and the rebuild does not carry your metadata across. It sticks only once the run has started, through PUT /processRuns/:id. If you need an external identifier on a queued entry, put it in title.

Session

Returned by POST /login and repeated under session in /init.

Field Type Set by client Meaning
id string no The session id, the same value as the cookie
createdAt timestamp no When you logged in
expiresAt timestamp no One month out. Optimistic, see below
deviceName string no The Kilobaser that issued the session
user.id string no The account id, which is what you log in with
user.name string no Display name, which is often not the id
user.fullName string no Longer name, may be empty
user.role string no user or admin

Sessions live in the device's memory. A restart or a software update destroys all of them long before expiresAt, so treat that field as an upper bound and handle 2-1-4 and 2-1-2 at any moment.

Machine status

The object under status in /init, returned by GET /status, and pushed as the status event. These are the fields a client actually reads; the rest are for the Kilobaser's own interface.

Field Type Set by client Meaning
deviceName string no The Kilobaser's name
serverTime timestamp no Device clock at the moment of the reply
currentState.mode string no What the machine is doing. ready when idle, then working, synthesis, check, canceling, emergencyStop and others
currentState.cartridgeType string no Cartridge the machine believes is loaded
currentState.chipKind string no Chip the machine believes is loaded
currentProcessRunId string no The run in progress. Empty when nothing is running
pendingAnswers array no Answer ids the machine is waiting for. Empty most of the time
pendingProcessRunIds array no Runs queued to start immediately after this one
currentRemainingTime number no Milliseconds left in the current step, when known
currentCheckpointProgress number no How far the current step has got
currentRunIndex number no Which of runIds is executing
runIds array no The planned processes of the current run
cancelLeaseExpiresAt timestamp no Present only while a cancel lease is held
lidOpenWarningTime timestamp no Set when the lid has been open too long
supportedOPModes object no Cartridge type to list of chip kinds. What this device can actually run
currentHWDState.chipKind string no Chip the sensor sees right now
currentHWDState.cartridgePresent boolean no Whether a cartridge is physically in place
currentHWDState.pressureHigh number no Supply pressure reading
updateRunning boolean no A software update is running; expect a restart
versionError object no Non-empty when the device configuration does not match the software
kbDevMode string no Developer mode of the device. Kilobaser reports the empty value

A checkpoint is currentState.mode == "check" and a non-empty pendingAnswers. Testing pendingAnswers alone will make you answer while the machine is still moving.

1.11 HTTP status codes

Status What it means here
200 Success. Some endpoints answer with an empty body, and a few echo what you sent rather than what was stored
400 The catch-all failure: bad input, wrong machine state, and a missing or expired session
403 Wrong credentials on login, or a role without rights for this route
404 An id that does not exist in the collection this endpoint looks in
409 A physical condition blocks the request, such as the lid or the cartridge not being where it must be
415 A body arrived without Content-Type: application/json
500 The device failed internally. A handful of plainly invalid requests also land here
503 The Kilobaser is still starting up. Retry-After is set and the body carries a state field

The one worth repeating: there is no 401. An expired session is a 400, in exactly the same shape as a malformed sequence. A client that decides when to log in again by looking at the status code will loop forever; decide by looking at the code.

Do not infer meaning from the status alone in the other direction either. 2-16-18, a username with invalid characters, is a 500. 2-11-34, starting a run that is not in the queue, is a 404. The code is the reliable part.

1.12 Endpoints this guide does not describe

The device serves a second set of routes used by Kilobaser to develop and service the Kilobaser: /processes, /protocols, /runs, /ccsettings, /instructions, /functions, /valveMappings, /settings, /fakehwd, /setfakehwd, /clearhwdqueue, /resetSettings, /errors/resumeProtocolCall, /errors/makeErrorCall, /errors/removeErrorCall and /errorSettings.

They are developer-only. A user or admin session gets 403 and 2-1-5 from all of them, they are not part of the supported interface, and they change without notice. They appear in older reference material, which is the only reason they are named here. Nothing in this guide needs them.

Two further endpoints exist only on the Kilobaser's own touchscreen port and are not reachable over the network at all: importing a sequence file from a USB stick, and reading a file off that stick. Use POST /processRuns/queueImportBrowser instead, which takes the file contents in the request.