API referencePlants
List plants
The workspace's plants, newest first, a page at a time. Pass externalId to find the one plant filed under your own identifier instead; the answer is still a list, with that plant or nothing, and meta.next_cursor is always null.
GET
https://app.xplantpro.com/ api/ v1/ plantsScope
read:plantsThe SDK takes external_id; the query parameter is externalId.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
externalId | string | No | Your own identifier for a plant, matched ignoring case. Returns that one plant, or an empty list; paging does not apply. |
limit | integer | No | Page size. Values above 200 are capped at 200. Default 50. From 1 to 200. |
offset | integer | No | Number of records to skip. Prefer cursor where a list offers it: an offset shifts when records are added ahead of it. Default 0. At least 0. |
cursor | string | No | Continue from the previous page: pass its meta.next_cursor unchanged, with the same filters. Treat it as opaque. Not combinable with offset. Up to 2048 characters. |
Example
curl "https://app.xplantpro.com/api/v1/plants?limit=50" \
-H "Authorization: Bearer $XPLANT_API_KEY"Response
200 with { "ok": true, "data": … }. data is an array. To get the next page, pass meta.next_cursor back as cursor; it is null on the last page. See Pagination.
| 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 |
|---|---|---|---|
next_cursor | string | null | Yes | Pass as cursor to fetch the next page. null means this is the last page. |
| Response header | Meaning |
|---|---|
X-Request-Id | Identifies this request. Include it when you contact support. |
Errors
| Status | Code | When |
|---|---|---|
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. |
422 | VALIDATION_ERROR | Both cursor and offset were sent; use one. |
422 | INVALID_CURSOR | The cursor is malformed, or came from a different list or different filters. Start again without it. |
429 | RATE_LIMIT_EXCEEDED | Too many requests for this key, device token or workspace. Wait Retry-After seconds. |
500 | PLANT_QUERY_FAILED | The plants could not be read. Retry later. |
Branch on code, never on the error text. See Errors.