xPlantAPI
API referenceExplants

Create an explant

Adds an explant to the workspace, recorded as created by the key's owner. Link it to the plant it was taken from with plant_id.

POST/api/v1/explants
Scope write:explantsHonours Idempotency-Key

Give it your own identifier in external_id to find it again with GET /api/v1/explants?externalId=. Fill in the lab's own fields with custom_fields: each value is checked against its field, and the whole request is refused if one does not fit.

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
labelstringYesThe culture's label — the name the lab knows it by. 1–200 characters.
plant_idstring | null (uuid)NoThe plant the explant was taken from. It must be a plant in the same workspace.
batch_numberstring | nullNoUp to 100 characters.
notesstring | nullNoUp to 5000 characters.
status"active" | "establishing" | "growing" | "needs_subculture" | "quarantined" | "senescing" | "discarded" | "retired" | "lost"NoWhere the culture stands. New explants default to active.
external_idstring | nullNoYour own identifier for this culture, such as a batch or line code from your own records. It must be unique in the workspace, ignoring case, and it is how GET /api/v1/explants?externalId= finds the explant again. Send null to clear it. 1–100 characters.
custom_fieldsobjectNoValues for the lab's own fields, keyed by each field's key as set up in the lab's settings. Each value must fit its field: text, a number, true or false, a date, or one of a pick-list's options (a date is stored as YYYY-MM-DD). A key the lab has not set up is refused, and the values may total at most 10,000 bytes. Send null as a value to leave a field empty.

Example

curl -X POST https://app.xplantpro.com/api/v1/explants \
  -H "Authorization: Bearer $XPLANT_API_KEY" \
  -H "Idempotency-Key: import-2026-09-25-line-0412" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Zebrina line A",
    "plant_id": "8c3f2d1a-6b4e-4f7a-9d2c-1e5b7a9c3f60",
    "status": "establishing",
    "external_id": "LINE-0412-A",
    "custom_fields": {
      "medium_lot": "MS-2609-03",
      "cytokinin_added": true
    }
  }'

Response

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

FieldTypeRequiredDescription
idstring (uuid)Yes—
labelstring | nullYesThe culture's label — the name the lab knows it by.
external_idstring | nullYesYour identifier for the culture: the external_id you gave it, otherwise its batch number, otherwise its label. Null when it has none of these.
statusstringYesWhere the culture stands, usually one of active, establishing, growing, needs_subculture, quarantined, senescing, discarded, retired, lost.
plant_idstring | nullYesThe plant the explant was taken from, when one is recorded.
workspace_idstring | nullYesThe workspace the explant belongs to.
initial_countinteger | nullYesThe count recorded when the culture was started.
current_countinteger | nullYesThe culture's count as last recorded.
created_atstring | nullYesISO 8601 timestamp.
custom_fieldsobjectYesThe lab's own fields for this record, keyed by each field's key as set up in the lab's settings. Values are text, numbers, true or false, or dates written as YYYY-MM-DD; a field left blank is absent or null. Empty when the lab has set up no fields.
Response
{
  "ok": true,
  "data": {
    "id": "b7e4a2c9-1f3d-4e8b-8a6c-5d2f9e1b7c34",
    "label": "Zebrina line A",
    "external_id": "LINE-0412-A",
    "status": "establishing",
    "plant_id": "8c3f2d1a-6b4e-4f7a-9d2c-1e5b7a9c3f60",
    "workspace_id": "3a9e7c21-5d4b-4c8f-a1e6-9b2d0f4c7e13",
    "initial_count": null,
    "current_count": null,
    "created_at": "2026-09-25T10:05:00.000Z",
    "custom_fields": {
      "medium_lot": "MS-2609-03",
      "cytokinin_added": true
    }
  }
}
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.
402PLAN_LIMIT_REACHEDThe key's owner has created as many explants as their plan allows.
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.
409IDEMPOTENCY_IN_FLIGHTA request with this Idempotency-Key is still being processed; retry after Retry-After seconds.
409DUPLICATE_ENTRYAnother explant in the workspace already uses this external_id, including one that has been deleted.
422VALIDATION_ERRORThe Idempotency-Key header is malformed.
422VALIDATION_ERRORA field failed validation. error names the first one, for example title: title is required.
422VALIDATION_ERRORplant_id is not a plant in the workspace.
422VALIDATION_ERRORcustom_fields names a field the lab has not set up, gives a field a value that does not fit it, or totals more than 10,000 bytes. error names the field.
429RATE_LIMIT_EXCEEDEDToo many requests for this key, device token or workspace. Wait Retry-After seconds.
500EXPLANT_CREATE_FAILEDThe explant could not be saved. Retry with the same Idempotency-Key.

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

On this page