xPlantAPI
API referenceSOPs and runs

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.

POST/api/v1/sop-runs/{id}/steps/{stepId}/events
Scope write:sop_stepsHonours Idempotency-Key

Evidence is append-only. There is no edit or delete — to correct something, post another event that says so. Send an Idempotency-Key so a scanner retrying on a patchy connection records one event rather than two.

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

NameTypeRequiredDescription
idstring (uuid)YesThe run's id.
stepIdstringYesThe step's id in the version the run follows, as Get an SOP lists it in version.steps. It is recorded as sent and not checked against the procedure.

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
event_type"confirmed" | "scanned" | "skipped" | "note" | "device_state"YesWhat happened at the step: confirmed (it was done), scanned (a label or vessel was scanned), skipped, note (a remark for whoever reads the run later) or device_state (what an instrument reported, such as a hood or autoclave cycle).
payloadobjectNoAny detail worth keeping with the event, as a JSON object — the code that was scanned, the note's text, the device's reading. Stored as sent. Default {}.
recorded_atstring (date-time)NoWhen it happened, in UTC with a trailing Z, such as 2026-09-25T08:30:00Z. A timestamp with an offset is refused. Defaults to when xPlant receives it.

Example

curl -X POST https://app.xplantpro.com/api/v1/sop-runs/2a4c6e8b-1d3f-4b5a-a7c9-e1f3a5b7c9d1/steps/step-3/events \
  -H "Authorization: Bearer $XPLANT_API_KEY" \
  -H "Idempotency-Key: station-3-wk38-step3-scan" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "scanned",
    "payload": {
      "code": "LINE-0412-J07"
    },
    "recorded_at": "2026-09-25T08:30:00Z"
  }'

Response

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

FieldTypeRequiredDescription
idstring (uuid)Yes—
runIdstring (uuid)YesThe run the evidence belongs to.
stepKeystringYesThe step it was recorded against — the stepId it was posted to.
eventTypestringYesconfirmed, scanned, skipped, note or device_state for a step event; measured for a measurement.
recordedAtstringYesWhen it happened: the recorded_at that was sent, or when xPlant received it.
payloadobjectYesThe detail sent with the event. For a measurement: metric, value, unit, and notes when there were any.
Response
{
  "ok": true,
  "data": {
    "id": "e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b",
    "runId": "9a8b7c6d-5e4f-4a3b-9c2d-1e0f9a8b7c6d",
    "stepKey": "step-3",
    "eventType": "scanned",
    "recordedAt": "2026-09-25T08:30:00+00:00",
    "payload": {
      "code": "LINE-0412-J07"
    }
  }
}
Response headerMeaning
Idempotent-Replaytrue when this response is a replay of an earlier request with the same Idempotency-Key.
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.
404NOT_FOUNDNo run with this id exists in the key's workspace, or the run id is not a well-formed id.
409IDEMPOTENCY_IN_FLIGHTA request with this Idempotency-Key is still being processed; retry after Retry-After seconds.
409SOP_RUN_CLOSEDThe run is complete. A completed run's record is final and takes no more evidence.
422VALIDATION_ERRORThe Idempotency-Key header is malformed.
422VALIDATION_ERRORA field failed validation — an event_type outside the list, or a recorded_at that is not a UTC timestamp. error gives the first problem but does not name the field.
429RATE_LIMIT_EXCEEDEDToo many requests for this key, device token or workspace. Wait Retry-After seconds.
500SOP_STEP_EVENT_CREATE_FAILEDThe evidence could not be saved. Retry with the same Idempotency-Key.

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

On this page