API referencePlants
Create a plant
Adds a plant to the workspace, recorded as created by the key's owner, and starts it in initial_stage.
POST
https://app.xplantpro.com/ api/ v1/ plantsScope
write:plantsHonours Idempotency-KeyGive it your own identifier in external_id to find it again with GET /api/v1/plants?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
| 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 |
|---|---|---|---|
species | string | Yes | The plant's species, for example Alocasia zebrina. 1–200 characters. |
common_name | string | null | No | The name the lab calls the plant. Without one, the plant is shown by its species. Up to 200 characters. |
genus | string | null | No | Up to 100 characters. |
family | string | null | No | Up to 100 characters. |
cultivar | string | null | No | Up to 200 characters. |
source | string | null | No | Where the plant came from — a supplier, a nursery or another collection. Up to 200 characters. |
notes | string | null | No | Up to 5000 characters. |
status | "active" | "dormant" | "harvested" | "contaminated" | "failed" | "in_culture" | "ready_for_transfer" | "quarantined" | "archived" | No | Where the plant stands in the lab. New plants default to active. |
initial_stage | "Mother Block" | "Acclimation" | "Production" | "Cold Storage" | "Quarantine" | "Propagation" | "Hardening Off" | "Greenhouse" | "Field" | "Discarded" | No | The stage the plant starts in. Defaults to Mother Block. |
external_id | string | null | No | Your own identifier for the plant, such as a line or accession code from your own records. It must be unique in the workspace, ignoring case, and it is how GET /api/v1/plants?externalId= finds the plant again. Send null to clear it. 1–100 characters. |
custom_fields | object | No | Values 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/plants \
-H "Authorization: Bearer $XPLANT_API_KEY" \
-H "Idempotency-Key: import-2026-09-25-row-0412" \
-H "Content-Type: application/json" \
-d '{
"species": "Alocasia zebrina",
"common_name": "Zebra Alocasia",
"genus": "Alocasia",
"source": "Stock line from the lab'\''s own collection",
"initial_stage": "Mother Block",
"external_id": "LINE-0412",
"custom_fields": {
"mother_stock_tray": "B4",
"weeks_in_culture": 12
}
}'Response
201 with { "ok": true, "data": … }. data holds the result.
| Field | Type | Required | Description |
|---|---|---|---|
id | string (uuid) | Yes | — |
name | string | Yes | What the lab calls the plant: its common name, or its species when it has none. |
species | string | Yes | — |
status | string | Yes | Where the plant stands in the lab, usually one of active, dormant, harvested, contaminated, failed, in_culture, ready_for_transfer, quarantined, archived. |
workspace_id | string | null | Yes | The workspace the plant belongs to. |
created_at | string | null | Yes | ISO 8601 timestamp. |
external_id | string | null | Yes | Your own identifier for the plant, exactly as it was given, or null when it has none. |
custom_fields | object | Yes | The 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. |
{
"ok": true,
"data": {
"id": "8c3f2d1a-6b4e-4f7a-9d2c-1e5b7a9c3f60",
"name": "Zebra Alocasia",
"species": "Alocasia zebrina",
"status": "active",
"workspace_id": "3a9e7c21-5d4b-4c8f-a1e6-9b2d0f4c7e13",
"created_at": "2026-09-25T09:30:00.000Z",
"external_id": "LINE-0412",
"custom_fields": {
"mother_stock_tray": "B4",
"weeks_in_culture": 12
}
}
}The envelope can also carry meta:
| Field | Type | Required | Description |
|---|---|---|---|
warning | string | Yes | Sent only when the plant was saved but its first stage could not be set. Record one with POST /api/v1/stages. |
| Response header | Meaning |
|---|---|
Idempotent-Replay | true when this response is a replay of an earlier request with the same Idempotency-Key. |
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. |
402 | PLAN_LIMIT_REACHED | The key's owner has created as many plants as their plan allows. error says which limit. |
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. |
409 | IDEMPOTENCY_IN_FLIGHT | A request with this Idempotency-Key is still being processed; retry after Retry-After seconds. |
409 | DUPLICATE_ENTRY | Another plant in the workspace already uses this external_id, including one that has been deleted. |
422 | VALIDATION_ERROR | The Idempotency-Key header is malformed. |
422 | VALIDATION_ERROR | A field failed validation. error names the first one, for example title: title is required. |
422 | VALIDATION_ERROR | custom_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. |
429 | RATE_LIMIT_EXCEEDED | Too many requests for this key, device token or workspace. Wait Retry-After seconds. |
500 | PLANT_CREATE_FAILED | The plant could not be saved. Retry with the same Idempotency-Key. |
Branch on code, never on the error text. See Errors.