ReferenceReference by module

Comments API

Every Comments action (9) and data model (3): endpoints, scopes, input, preconditions, events and examples.

Notes and replies on any record, for your team.

Module code comments · 9 actions · 3 data models · 9 events. A key or token never does more here than the person behind it can; row-level security applies exactly as in the app. Scopes: comments (everything), comments:read (read only) or comments:<capability>.

Resources

ResourceTableList and readPOSTPATCHDELETE
comment_mentionscomment_mention/api/v1/comment_mentions
comment_reactionscomment_reaction/api/v1/comment_reactions
commentscomment/api/v1/commentscomments.delete

Lists take limit (up to 200), cursor, order (e.g. -created_at), fields and q; every other query parameter is a column filter: ?status=paid, ?total[gte]=100, ?id[in]=a,b, ?x=null.

Actions

ActionNeedsWhat it does
comments.deletecomments:readDelete a comment
comments.editcomments:readEdit a comment
comments.postcomments:readComment on a record
comments.publishcomments:readPublish a comment
comments.reactcomments:readReact to a comment
comments.reopencomments:readReopen a thread
comments.replycomments:readReply to a comment
comments.resolvecomments:readResolve a thread
comments.unpublishcomments:readUnpublish a comment

comments.delete

Delete a comment — Removes a comment from the thread. Replies stay and become roots.

Needs comments:read · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/comments/{id}/actions/delete
API key or OAuth token · comments:read
  • REST alias: DELETE /api/v1/comments/{id}
  • Canonical address: POST /api/v1/actions/comments.delete

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Comment · id of comment

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
comment_not_foundThe comment must exist.
cannot_delete_commentRemoving somebody else’s comment needs delete on the target’s module.

Events it publishes: comments.deleted

What it writes: comment (update) — Stamps deleted_at

curl -X POST https://app.getera.io/api/v1/comments/COMMENT_ID/actions/delete \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "comments.deleted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.comments.delete("COMMENT_ID")
era comments delete COMMENT_ID
tools/call
{
  "name": "era__comments__delete",
  "arguments": {
    "id": "COMMENT_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold comments:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 comment_not_found, cannot_delete_comment · 429 slow down

comments.edit

Edit a comment — Rewrites a comment you wrote, and says on screen that it changed.

Needs comments:read · changes data

POSThttps://app.getera.io/api/v1/comments/{id}/actions/edit
API key or OAuth token · comments:read
  • Canonical address: POST /api/v1/actions/comments.edit

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Comment · id of comment
bodystringyesComment · max 20000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
comment_not_foundThe comment must exist.
not_authorOnly the author may change the words.
empty_bodyA comment must have words in it.
mentioned_cannot_readNobody may be mentioned on a record they cannot open.

Events it publishes: comments.edited, comments.mentioned

What it writes: comment (update) — Rewrites the body and stamps edited_at; comment_mention (insert) — Records anyone newly mentioned

curl -X POST https://app.getera.io/api/v1/comments/COMMENT_ID/actions/edit \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"body":"Comment"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "comments.edited",
    "comments.mentioned"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.comments.edit("COMMENT_ID", {
  body: "Comment"
})
era comments edit COMMENT_ID \
  --body "Comment"
tools/call
{
  "name": "era__comments__edit",
  "arguments": {
    "id": "COMMENT_ID",
    "body": "Comment"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold comments:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 comment_not_found, not_author, empty_body, mentioned_cannot_read · 429 slow down

comments.post

Comment on a record — Adds a comment to a record. Internal until somebody publishes it.

Needs comments:read · changes data

POSThttps://app.getera.io/api/v1/comments/actions/post
API key or OAuth token · comments:read
  • Canonical address: POST /api/v1/actions/comments.post

Input

FieldTypeRequiredNotes
recordTypestringyesRecord type · max 60
recordIduuidyesRecord
bodystringyesComment · max 20000
mentionsobject / arrayMentions

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
unknown_record_typeThe record type must be one a module owns.
cannot_commentCommenting needs the comment capability on the target’s module.
empty_bodyA comment must have words in it.
record_not_foundThe record must exist.
mentioned_cannot_readNobody may be mentioned on a record they cannot open.

Events it publishes: comments.posted, comments.mentioned

What it writes: comment (insert) — Writes the comment; comment_mention (insert) — Records who was mentioned

curl -X POST https://app.getera.io/api/v1/comments/actions/post \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"recordType":"Record type","recordId":"RECORD_ID","body":"Comment"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "comments.posted",
    "comments.mentioned"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.comments.post({
  recordType: "Record type",
  recordId: "RECORD_ID",
  body: "Comment"
})
era comments post \
  --record-type "Record type" \
  --record-id "RECORD_ID" \
  --body "Comment"
tools/call
{
  "name": "era__comments__post",
  "arguments": {
    "recordType": "Record type",
    "recordId": "RECORD_ID",
    "body": "Comment"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold comments:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 unknown_record_type, cannot_comment, empty_body, record_not_found, mentioned_cannot_read · 429 slow down

comments.publish

Publish a comment — Shows the comment on the storefront. Not something a default does.

Needs comments:read · reaches outside (sends, publishes or charges) · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/comments/{id}/actions/publish
API key or OAuth token · comments:read
  • Canonical address: POST /api/v1/actions/comments.publish

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Comment · id of comment

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
comment_not_foundThe comment must exist.
cannot_manage_recordPublishing needs manage on the target’s module.
is_a_replyA reply is published with its thread.
already_publicThe comment must be private.

Events it publishes: comments.published

What it writes: comment (update) — Sets is_public

curl -X POST https://app.getera.io/api/v1/comments/COMMENT_ID/actions/publish \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "comments.published"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.comments.publish("COMMENT_ID")
era comments publish COMMENT_ID
tools/call
{
  "name": "era__comments__publish",
  "arguments": {
    "id": "COMMENT_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold comments:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 comment_not_found, cannot_manage_record, is_a_reply, already_public · 429 slow down

comments.react

React to a comment — Adds your reaction to a comment, or takes it back if you already gave it.

Needs comments:read · removes or cannot be undone

POSThttps://app.getera.io/api/v1/comment_reactions/actions/react
API key or OAuth token · comments:read
  • Canonical address: POST /api/v1/actions/comments.react

Input

FieldTypeRequiredNotes
iduuidyesComment · id of comment
reactionstringyesReaction · max 32

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
invalid_reactionThe reaction must be one of the eight offered.
comment_not_foundThe comment must exist.
cannot_commentReacting needs the comment capability on the target’s module.

Events it publishes: comments.reacted

What it writes: comment_reaction (insert) — Adds the reaction; comment_reaction (delete) — Takes a reaction back

curl -X POST https://app.getera.io/api/v1/comment_reactions/actions/react \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"id":"COMMENT_ID","reaction":"Reaction"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "comments.reacted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.commentReactions.react({
  id: "COMMENT_ID",
  reaction: "Reaction"
})
era comment_reactions react \
  --id "COMMENT_ID" \
  --reaction "Reaction"
tools/call
{
  "name": "era__comments__react",
  "arguments": {
    "id": "COMMENT_ID",
    "reaction": "Reaction"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold comments:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 invalid_reaction, comment_not_found, cannot_comment · 429 slow down

comments.reopen

Reopen a thread — Puts a resolved thread back on the list.

Needs comments:read · changes data

POSThttps://app.getera.io/api/v1/comments/{id}/actions/reopen
API key or OAuth token · comments:read
  • Canonical address: POST /api/v1/actions/comments.reopen

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Comment · id of comment

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
comment_not_foundThe comment must exist.
cannot_commentReopening needs the comment capability on the target’s module.
not_resolvedThe thread must be resolved.

Events it publishes: comments.reopened

What it writes: comment (update) — Clears resolved_at

curl -X POST https://app.getera.io/api/v1/comments/COMMENT_ID/actions/reopen \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "comments.reopened"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.comments.reopen("COMMENT_ID")
era comments reopen COMMENT_ID
tools/call
{
  "name": "era__comments__reopen",
  "arguments": {
    "id": "COMMENT_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold comments:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 comment_not_found, cannot_comment, not_resolved · 429 slow down

comments.reply

Reply to a comment — Answers a comment. Replies go one level deep and no further.

Needs comments:read · changes data

POSThttps://app.getera.io/api/v1/comments/{id}/actions/reply
API key or OAuth token · comments:read
  • Canonical address: POST /api/v1/actions/comments.reply

Input

FieldTypeRequiredNotes
parentIduuidyesFilled from the path {id} · Comment · id of comment
bodystringyesReply · max 20000
mentionsobject / arrayMentions

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
parent_not_foundThe comment being replied to must exist.
parent_is_a_replyA reply may not be replied to.
cannot_commentReplying needs the comment capability on the target’s module.
empty_bodyA reply must have words in it.
mentioned_cannot_readNobody may be mentioned on a record they cannot open.

Events it publishes: comments.posted, comments.mentioned

What it writes: comment (insert) — Writes the reply; comment_mention (insert) — Records who was mentioned

curl -X POST https://app.getera.io/api/v1/comments/COMMENT_ID/actions/reply \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"body":"Reply"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "comments.posted",
    "comments.mentioned"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.comments.reply("COMMENT_ID", {
  body: "Reply"
})
era comments reply COMMENT_ID \
  --body "Reply"
tools/call
{
  "name": "era__comments__reply",
  "arguments": {
    "parentId": "COMMENT_ID",
    "body": "Reply"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold comments:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 parent_not_found, parent_is_a_reply, cannot_comment, empty_body, mentioned_cannot_read · 429 slow down

comments.resolve

Resolve a thread — Marks the thread as settled, so the panel is a list of what is left.

Needs comments:read · changes data

POSThttps://app.getera.io/api/v1/comments/{id}/actions/resolve
API key or OAuth token · comments:read
  • Canonical address: POST /api/v1/actions/comments.resolve

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Comment · id of comment

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
comment_not_foundThe comment must exist.
cannot_commentResolving needs the comment capability on the target’s module.
is_a_replyA reply shares its thread’s state.
already_resolvedThe thread must be open.

Events it publishes: comments.resolved

What it writes: comment (update) — Stamps resolved_at

curl -X POST https://app.getera.io/api/v1/comments/COMMENT_ID/actions/resolve \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "comments.resolved"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.comments.resolve("COMMENT_ID")
era comments resolve COMMENT_ID
tools/call
{
  "name": "era__comments__resolve",
  "arguments": {
    "id": "COMMENT_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold comments:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 comment_not_found, cannot_comment, is_a_reply, already_resolved · 429 slow down

comments.unpublish

Unpublish a comment — Takes a published comment back off the storefront.

Needs comments:read · changes data

POSThttps://app.getera.io/api/v1/comments/{id}/actions/unpublish
API key or OAuth token · comments:read
  • Canonical address: POST /api/v1/actions/comments.unpublish

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Comment · id of comment

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
comment_not_foundThe comment must exist.
cannot_manage_recordUnpublishing needs manage on the target’s module.
already_privateThe comment must be public.

Events it publishes: comments.unpublished

What it writes: comment (update) — Clears is_public

curl -X POST https://app.getera.io/api/v1/comments/COMMENT_ID/actions/unpublish \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "comments.unpublished"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.comments.unpublish("COMMENT_ID")
era comments unpublish COMMENT_ID
tools/call
{
  "name": "era__comments__unpublish",
  "arguments": {
    "id": "COMMENT_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold comments:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 comment_not_found, cannot_manage_record, already_private · 429 slow down

Data models

CommentMention

Table comment_mention · Resource comment_mentions

  • GET /api/v1/comment_mentions
  • GET /api/v1/comment_mentions/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
comment_idstring (uuid) · uuidcomment
user_idstring (uuid) · uuidapp_user
created_atstring (date-time) · timestamptz

Primary key: id

CommentReaction

Table comment_reaction · Resource comment_reactions

  • GET /api/v1/comment_reactions
  • GET /api/v1/comment_reactions/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
comment_idstring (uuid) · uuidcomment
user_idstring (uuid) · uuidapp_user
reactionstring · text
created_atstring (date-time) · timestamptz

Primary key: id

Unique: comment_id, user_id, reaction

Checks:

  • CHECK (((length(reaction) >= 1) AND (length(reaction) <= 32)))

Comment

Table comment · Resource comments

  • GET /api/v1/comments
  • GET /api/v1/comments/{id}
  • DELETE /api/v1/comments/{id} → comments.delete
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
record_typestring · text
record_idstring (uuid) · uuid
bodystring · text
author_user_idstring (uuid) · uuidyesapp_user
author_labelstring · textyes
is_publicboolean · bool
parent_idstring (uuid) · uuidyescomment
resolved_atstring (date-time) · timestamptzyes
resolved_by_user_idstring (uuid) · uuidyesapp_user
edited_atstring (date-time) · timestamptzyes
deleted_atstring (date-time) · timestamptzyes
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Checks:

  • CHECK ((length(btrim(body)) > 0))
  • CHECK (((parent_id IS NULL) OR (parent_id <> id)))
  • CHECK (((resolved_at IS NULL) OR (parent_id IS NULL)))
  • CHECK (((resolved_at IS NULL) = (resolved_by_user_id IS NULL)))

Events

Workflows and webhooks react to these events.

EventWhat happensPayload
comments.deletedA comment was removed from the thread.id
comments.editedA comment was rewritten by its author.id
comments.mentionedSomebody was mentioned in a comment. One event per newly mentioned person.id, commentId, mentionedUserId, recordType, recordId, authorUserId
comments.postedA comment or reply was written.id, recordType, recordId
comments.publishedA comment was shown on the storefront.id
comments.reactedA reaction was added to, or taken back from, a comment.id, reaction, added, authorUserId
comments.reopenedA settled thread was reopened.id
comments.resolvedA thread was marked settled.id
comments.unpublishedA comment was taken off the storefront.id