@shmaplex/xplant-sdk 0.7.0 is out: what's new →
xPlantAPI
API referenceSOPs and runs

Start an SOP run

Starts a run of an SOP: the record that a procedure was carried out, step by step, against the version the lab had in force.

POST/api/v1/sop-runs
Scope write:sop_runsHonours Idempotency-Key

A bench station typically:

  1. Reads the SOP with Get an SOP and shows the steps of the version in force.
  2. Starts a run here, naming the batch or line it is for in batch_code.
  3. Posts evidence against each step as the work happens — a confirmation, a scanned vessel label, a reading from a balance or pH meter — with Record a step event and Record a step measurement.

The run follows the version in force when it starts, and you cannot choose another. Send an Idempotency-Key so a retried start does not open a second run.

The run is recorded as the key's owner, and your lab's training rule applies to them exactly as it does in xPlant. Where the lab requires current training before an SOP is run, a key whose owner has none on this SOP is refused. Where the lab only asks for a warning, the run starts and meta.training_warning says what is missing, so the station can tell the person running it.

See also: Run an SOP from a bench station.

Send an Idempotency-Key header to make retries safe: a repeat with the same key within 24 hours returns the first response instead of writing twice. See Idempotency.

Headers

NameTypeRequiredDescription
Idempotency-KeystringNoAny unique string you choose per logical write. A retry carrying the same key within 24 hours returns the first result instead of writing again. Scoped to your API key and this operation. 8–255 characters. Must match ^[A-Za-z0-9._:~-]+$.

Request body

FieldTypeRequiredDescription
sop_idstring (uuid)YesThe SOP to run. It must have a version in force.
batch_codestringNoYour lab's own identifier for what is being run, such as a batch or line code. Up to 120 characters.
plant_idstring (uuid)NoThe plant the run is for, when there is one. It must be in this workspace.

Example

curl -X POST https://app.xplantpro.com/api/v1/sop-runs \
  -H "Authorization: Bearer $XPLANT_API_KEY" \
  -H "Idempotency-Key: station-3-wk38-start" \
  -H "Content-Type: application/json" \
  -d '{
    "sop_id": "2e4f6a8c-0b1d-4e3f-9a5b-7c9d1e3f5a7b",
    "batch_code": "LINE-0412"
  }'

Response

201 with { "ok": true, "data": … }. data holds the result.

FieldTypeRequiredDescription
idstring (uuid)Yes—
sopIdstring | null (uuid)YesThe SOP being run.
versioninteger | nullYesThe version of the SOP this run follows — the one in force when it started. It never changes afterwards.
versionIdstring | null (uuid)YesThat version's id.
statusstringYesin_progress from the moment a run starts. A run ends as completed, failed or cancelled, closed in xPlant or with Complete an SOP run; runs can also be pending, on_hold or archived.
batchCodestring | nullYesYour lab's own identifier for what is being run.
startedAtstring | nullYes—
completedAtstring | nullYesWhen the run was completed. Empty while it runs, and for a run that ended failed or cancelled.
progressnumberYesHow far through its steps the run is, from 0 to 100, as ticked off in xPlant.
stepsany[]YesThe step checklist as ticked off in xPlant, one entry per step, such as { "id": "step-3", "completed": true }. Empty until someone works the run in xPlant. Evidence posted through the API is in events and does not tick steps off here.
Response
{
  "ok": true,
  "data": {
    "id": "9a8b7c6d-5e4f-4a3b-9c2d-1e0f9a8b7c6d",
    "sopId": "2e4f6a8c-0b1d-4e3f-9a5b-7c9d1e3f5a7b",
    "version": 2,
    "versionId": "5c6d7e8f-9a0b-4c1d-8e2f-3a4b5c6d7e8f",
    "status": "in_progress",
    "batchCode": "LINE-0412",
    "startedAt": "2026-09-25T08:02:13.000Z",
    "completedAt": null,
    "progress": 0,
    "steps": []
  }
}

The envelope can also carry meta:

FieldTypeRequiredDescription
training_warningobjectYesSent when your lab enforces training and the key's owner's training on this SOP needs their attention: it is missing, expired or revoked and the lab warns rather than refuses, or it is current but lapses within 30 days. The run has started either way. Left out otherwise.
training_warning.qualification"untrained" | "expired" | "revoked" | "expiring"YesWhere the key's owner stands on this SOP: untrained when no training is recorded, expired when it has lapsed, revoked when it was withdrawn, expiring when it is current but lapses within 30 days.
training_warning.expires_onstring | nullYesThe day that training lapsed or lapses, as YYYY-MM-DD, for expired and expiring. Null otherwise.
Response headerMeaning
Idempotent-Replaytrue when this response is a replay of an earlier request with the same Idempotency-Key.
X-RateLimit-LimitThe request budget this answer reports on, per minute: your key's or device token's (1,000) or your workspace's (3,000), whichever has fewer requests left. Left out when the budget could not be read.
X-RateLimit-RemainingRequests left in that budget this minute, after this one. 0 on a 429. A workspace's other keys spend its budget too, so this can fall faster than your own requests alone would.
X-RateLimit-ResetWhole seconds until that budget's minute ends and it is full again. Never more than 60.
X-Request-IdIdentifies this request. Include it when you contact support.

Errors

StatusCodeWhen
400VALIDATION_ERRORThe request body is not valid JSON.
401UNAUTHORIZEDThe key is missing, malformed or revoked, or its owner is no longer a member of the workspace.
402PAID_PLAN_REQUIREDThe workspace's plan does not include the API. The full API is included with xPlant+ Teams and Enterprise; on Hobby and Pro Lab, keys can connect devices only.
403FORBIDDENThe key lacks a scope this operation requires, or its owner's current role in the workspace cannot use it — a key never does more than its owner can in xPlant. error names the scope, and for a role, the role it needs.
403DEVICE_TOKEN_NOT_ACCEPTEDA device token was sent; this operation needs a workspace API key.
403TRAINING_REQUIREDYour lab requires current training before an SOP is run, and the key's owner has none on this one: it was never recorded, has expired, or was revoked. Nothing is started. Once their training is recorded in xPlant, start the run again.
404NOT_FOUNDThe SOP, or the plant named in plant_id, is not in this workspace.
409IDEMPOTENCY_IN_FLIGHTA request with this Idempotency-Key is still being processed; retry after Retry-After seconds.
409SOP_RUN_NOT_EFFECTIVEThe SOP has no version in force, so there is nothing approved to run. Put a version into force in xPlant, then start the run.
422VALIDATION_ERRORThe Idempotency-Key header is malformed.
422VALIDATION_ERRORA field failed validation, for example sop_id is missing or is not an id. error names the field with the first problem, for example sop_id: Invalid uuid.
429RATE_LIMIT_EXCEEDEDToo many requests for this key, device token or workspace. Wait Retry-After seconds.
500SOP_RUN_CREATE_FAILEDThe run could not be started. Retry with the same Idempotency-Key.

Branch on code, never on the error text. See Errors.

On this page