xPlantAPI
API referenceTransfers and stages

Advance a stage

Moves a plant or explant into a new stage in one call: the stage it is in now is marked completed, the new one is recorded, and it becomes the current stage. Send exactly one of plant_id or explant_id.

POST/api/v1/stages
Scope write:transfersHonours Idempotency-Key

Every successful move answers with meta beside the stage: meta.previous_stage_id names the stage that was closed, so your system can mirror the change without reading the history back. Send an Idempotency-Key when you might retry: a repeated move would otherwise close the stage the first attempt opened.

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
plant_idstring (uuid)NoThe plant this is for. Send exactly one of plant_id or explant_id.
explant_idstring (uuid)NoThe explant this is for. Send exactly one of plant_id or explant_id.
stagestringYesThe stage to move into, as a key from your lab's stage list — for example multiplication or root_induction. It is stored as sent and not checked against the list, so send a key your lab already uses. 1–50 characters.
entered_onstringNoWhen it entered the stage: a date such as 2026-09-24, or a full ISO 8601 timestamp. Defaults to today (UTC).
room_idstring (uuid)NoThe growing room it is in for this stage. Must be a room in the workspace.
notesstringNoUp to 5000 characters.

Example

curl -X POST https://app.xplantpro.com/api/v1/stages \
  -H "Authorization: Bearer $XPLANT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "explant_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
    "stage": "multiplication",
    "entered_on": "2026-09-24",
    "notes": "Shoot clusters forming well on the Alocasia line."
  }'

Response

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

FieldTypeRequiredDescription
idstring (uuid)Yes—
entity_type"plant" | "explant"YesWhether the stage belongs to a plant or an explant.
entity_idstring (uuid)YesThe plant's or explant's id.
stagestringYesThe stage, usually as a key from your lab's stage list such as multiplication. Records made by older tools can carry the stage's display name instead, such as Multiplication.
statusstringYesactive for the stage the plant or explant is in now, completed for one it has moved on from. Stages can also be failed or archived.
entered_onstring | nullYesWhen it entered this stage, as an ISO 8601 timestamp.
completed_atstring | nullYesWhen it moved on from this stage. Null while the stage is current.
room_idstring | null (uuid)YesThe room it was in for this stage, when one was recorded.
notesstring | nullYes—
created_atstring | nullYes—
Response
{
  "ok": true,
  "data": {
    "id": "6e5d4c3b-2a19-4807-96a5-b4c3d2e1f0a9",
    "entity_type": "explant",
    "entity_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
    "stage": "multiplication",
    "status": "active",
    "entered_on": "2026-09-24T00:00:00+00:00",
    "completed_at": null,
    "room_id": null,
    "notes": "Shoot clusters forming well on the Alocasia line.",
    "created_at": "2026-09-24T08:41:17.000Z"
  }
}

The envelope can also carry meta:

FieldTypeRequiredDescription
previous_stage_idstring | null (uuid)NoThe stage this one replaced, which is now completed. Null when there was no current stage.
warningstringNoSent instead of previous_stage_id when the stage was saved but could not be made the current one. The history is complete; set the current stage in xPlant.
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_FOUNDThe plant or explant, or the growing room named in room_id, is not in this workspace. Nothing was changed.
409IDEMPOTENCY_IN_FLIGHTA request with this Idempotency-Key is still being processed; retry after Retry-After seconds.
422VALIDATION_ERRORThe Idempotency-Key header is malformed.
422VALIDATION_ERRORA field failed validation, or neither or both of plant_id and explant_id were sent. error names the first problem, for example stage: stage is required.
429RATE_LIMIT_EXCEEDEDToo many requests for this key, device token or workspace. Wait Retry-After seconds.
500STAGE_ADVANCE_FAILEDThe stage could not be saved. Retry with the same Idempotency-Key.

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

On this page