Record a step measurement
Records a numeric reading against one step of a run — the pH of a medium, the mass of an ingredient, a temperature — with its unit, as the bench station running the SOP reads it from a balance, pH meter or probe.
https://app.xplantpro.com/ api/ v1/ sop-runs/ {id}/ steps/ {stepId}/ measurementswrite:sop_stepsHonours Idempotency-KeyThe reading joins the same trail as the step events, with eventType measured, so a run reads in one order. The unit is required: a number without one is not a record anyone can rely on later. Send an Idempotency-Key so a retried post does not record the reading twice.
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.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string (uuid) | Yes | The run's id. |
stepId | string | Yes | The id of one of the steps in the version the run follows — the version in force when the run started, whose steps Get an SOP lists in version.steps while it is still in force. Any other stepId is refused and nothing is recorded. |
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Idempotency-Key | string | No | Any 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
| Field | Type | Required | Description |
|---|---|---|---|
metric | string | Yes | What was measured, in your own words — temperature, ph, mass. 1–60 characters. |
value | number | Yes | The reading. |
unit | string | Yes | The unit the reading is in, such as C, pH or g. Required. 1–20 characters. |
recorded_at | string (date-time) | No | When it happened, as an ISO 8601 timestamp in UTC (2026-09-25T08:30:00Z) or with an offset (2026-09-25T10:30:00+02:00). Defaults to when xPlant receives it. |
notes | string | No | Anything the reading needs beside it. Up to 500 characters. |
Example
curl -X POST https://app.xplantpro.com/api/v1/sop-runs/2a4c6e8b-1d3f-4b5a-a7c9-e1f3a5b7c9d1/steps/step-3/measurements \
-H "Authorization: Bearer $XPLANT_API_KEY" \
-H "Idempotency-Key: station-3-wk38-step3-ph" \
-H "Content-Type: application/json" \
-d '{
"metric": "ph",
"value": 5.7,
"unit": "pH",
"recorded_at": "2026-09-25T08:21:40Z",
"notes": "Initiation medium before pouring."
}'Response
201 with { "ok": true, "data": … }. data holds the result.
| Field | Type | Required | Description |
|---|---|---|---|
id | string (uuid) | Yes | — |
runId | string (uuid) | Yes | The run the evidence belongs to. |
stepKey | string | Yes | The step it was recorded against — the stepId it was posted to. |
eventType | string | Yes | confirmed, scanned, skipped, note or device_state for a step event; measured for a measurement. |
recordedAt | string | Yes | When it happened: the recorded_at that was sent, or when xPlant received it. |
payload | object | Yes | The detail sent with the event. For a measurement: metric, value, unit, and notes when there were any. |
{
"ok": true,
"data": {
"id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
"runId": "9a8b7c6d-5e4f-4a3b-9c2d-1e0f9a8b7c6d",
"stepKey": "step-2",
"eventType": "measured",
"recordedAt": "2026-09-25T08:21:40+00:00",
"payload": {
"metric": "ph",
"value": 5.7,
"unit": "pH",
"notes": "Initiation medium before pouring."
}
}
}| Response header | Meaning |
|---|---|
Idempotent-Replay | true when this response is a replay of an earlier request with the same Idempotency-Key. |
X-RateLimit-Limit | The 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-Remaining | Requests 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-Reset | Whole seconds until that budget's minute ends and it is full again. Never more than 60. |
X-Request-Id | Identifies this request. Include it when you contact support. |
Errors
| Status | Code | When |
|---|---|---|
400 | VALIDATION_ERROR | The request body is not valid JSON. |
401 | UNAUTHORIZED | The key is missing, malformed or revoked, or its owner is no longer a member of the workspace. |
402 | PAID_PLAN_REQUIRED | The 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. |
403 | FORBIDDEN | The 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. |
403 | DEVICE_TOKEN_NOT_ACCEPTED | A device token was sent; this operation needs a workspace API key. |
404 | NOT_FOUND | No run with this id exists in the key's workspace, or the run id is not a well-formed id. |
404 | NOT_FOUND | stepId is not the id of a step in the version the run follows, or the run follows no recorded version of its SOP and so has no steps to record against. Nothing is recorded. |
409 | IDEMPOTENCY_IN_FLIGHT | A request with this Idempotency-Key is still being processed; retry after Retry-After seconds. |
409 | SOP_RUN_CLOSED | The run has ended: its status is one of completed, failed, cancelled, archived. An ended run's record is final and takes no more evidence. |
422 | VALIDATION_ERROR | The Idempotency-Key header is malformed. |
422 | VALIDATION_ERROR | A field failed validation — a missing unit, a value that is not a number, or a recorded_at that is not a timestamp with a time zone. error names the field with the first problem, for example sop_id: Invalid uuid. |
429 | RATE_LIMIT_EXCEEDED | Too many requests for this key, device token or workspace. Wait Retry-After seconds. |
500 | SOP_STEP_EVENT_CREATE_FAILED | The evidence could not be saved. Retry with the same Idempotency-Key. |
Branch on code, never on the error text. See Errors.
Record step evidence
Records what happened at one step of a run: someone confirmed it, scanned a label or vessel, skipped it, or left a note, or an instrument reported its state.
List SOPs
The workspace's standard operating procedures, most recently updated first — drafts and archived ones included, with status saying which. Summaries only: fetch one SOP to read the steps of the version in force.