xPlantAPI
API referenceComments

Add a comment

Adds a comment to a plant, explant, contamination log, task, media recipe or SOP, as the key's owner. It is the same comment the app makes: members it names are notified, the author of the comment it replies to is told, the people following a task hear about it, and it appears in the record's activity.

POST/api/v1/comments
Scope write:commentsHonours Idempotency-Key

The key's owner needs the member role or above in the workspace, as in the app.

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
entity_type"plant" | "explant" | "contamination" | "task" | "media_recipe" | "sop"YesThe kind of record to comment on.
entity_idstring (uuid)YesThe id of the record to comment on.
bodystringYesThe comment, in Markdown. Stored exactly as sent. To mention someone, write @ and their username in the text and add their user id to mentioned_user_ids. To link a record, write #plant: (or #explant:, #contamination:, #task:, #media:, #sop:) followed by its name, and list it in references. 1–5000 characters.
parent_idstring (uuid)NoReply to this comment. It must be on the same record.
mentioned_user_idsstring (uuid)[]NoWorkspace members this comment names. Each is notified, exactly as when someone is mentioned in the app. Every id must be an active member of the workspace. Up to 25 items.
referencesobject[]NoRecords in this workspace that the body links to. Up to 25 items.
references[].entity_type"plant" | "explant" | "contamination" | "task" | "media_recipe" | "sop"YesThe kind of record the comment links to.
references[].entity_idstring (uuid)YesThe linked record's id.
references[].labelstringYesThe record's name as it follows #type: in the body, where spaces are written as hyphens; either spelling is accepted here. The link is drawn over the matching text. 1–200 characters.

Example

curl -X POST https://app.xplantpro.com/api/v1/comments \
  -H "Authorization: Bearer $XPLANT_API_KEY" \
  -H "Idempotency-Key: bench-3-line-0412-note-1" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_type": "explant",
    "entity_id": "6d2f9a14-8b3e-4c71-a5d0-1f7e3b8c2a96",
    "body": "@sam the Alocasia line on shelf 2 is ready to go onto fresh medium. See #task:Subculture-Alocasia-line.",
    "mentioned_user_ids": [
      "4a8f1c63-2e7d-4b95-8c10-5d3e9f7a2b68"
    ],
    "references": [
      {
        "entity_type": "task",
        "entity_id": "5b0f6f3e-2c1a-4d8e-9f47-0a6c3e1b7d22",
        "label": "Subculture Alocasia line"
      }
    ]
  }'

Response

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

FieldTypeRequiredDescription
idstring (uuid)Yes—
entity_type"plant" | "explant" | "contamination" | "task" | "media_recipe" | "sop"YesThe kind of record the comment is on.
entity_idstring (uuid)YesThe record the comment is on.
parent_idstring | null (uuid)YesThe comment this one replies to.
bodystringYesThe comment in Markdown, exactly as written — mentions and record links included as the @name and #type:Label text the author typed.
statusstringYesactive; edited once changed after posting; or deleted, which keeps the comment's place in the thread but not its text.
is_pinnedbooleanYesPinned to the top of the record's discussion.
authorobjectYes—
author.idstring (uuid)YesUser id of the author.
author.namestring | nullYesThe name shown beside the comment in the app, or null when there is none to show.
mentioned_user_idsstring (uuid)[]YesWorkspace members the comment named. Each was notified.
referencesobject[]YesRecords in the workspace the body links to. A record removed since is left out.
references[].entity_type"plant" | "explant" | "contamination" | "task" | "media_recipe" | "sop"Yes—
references[].entity_idstring (uuid)Yes—
references[].labelstringYesThe name the body links from.
created_atstring | nullYesISO 8601.
updated_atstring | nullYesISO 8601.
edited_atstring | nullYesWhen the text was last changed. ISO 8601.
Response
{
  "ok": true,
  "data": {
    "id": "9c4e2a71-3d5b-4f86-b1e0-7a2d6c8f3e45",
    "entity_type": "explant",
    "entity_id": "6d2f9a14-8b3e-4c71-a5d0-1f7e3b8c2a96",
    "parent_id": null,
    "body": "@sam the Alocasia line on shelf 2 is ready to go onto fresh medium. See #task:Subculture-Alocasia-line.",
    "status": "active",
    "is_pinned": false,
    "author": {
      "id": "0d7e4b9a-6f21-4c3e-8a5b-2e9f1c7d4a60",
      "name": "Sam Okafor"
    },
    "mentioned_user_ids": [
      "4a8f1c63-2e7d-4b95-8c10-5d3e9f7a2b68"
    ],
    "references": [
      {
        "entity_type": "task",
        "entity_id": "5b0f6f3e-2c1a-4d8e-9f47-0a6c3e1b7d22",
        "label": "Subculture Alocasia line"
      }
    ],
    "created_at": "2026-09-25T09:15:40.000Z",
    "updated_at": "2026-09-25T09:15:40.000Z",
    "edited_at": null
  }
}
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.
403FORBIDDENThe key's owner is below the member role in the workspace. A key never does more than its owner can in xPlant; error names the role needed.
404NOT_FOUNDentity_id names no record of that entity_type in the workspace, or parent_id names no comment on it; error says which.
409IDEMPOTENCY_IN_FLIGHTA request with this Idempotency-Key is still being processed; retry after Retry-After seconds.
409CONFLICTThe task's discussion is locked. Only the task's creator or a lab manager can comment.
422VALIDATION_ERRORThe Idempotency-Key header is malformed.
422VALIDATION_ERRORA field failed validation. error names the first one, for example title: title is required.
422VALIDATION_ERRORA mentioned user is not an active member of the workspace, or a linked record is not in it.
429RATE_LIMIT_EXCEEDEDToo many requests for this key, device token or workspace. Wait Retry-After seconds.
500COMMENT_CREATE_FAILEDThe comment could not be saved. Retry with the same Idempotency-Key.

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

On this page