API reference

Conversations

16 endpoints, served at https://orbitwrite.com/api/v1. Each one lists the credentials it accepts, its parameters and every response it can give.

List inbox conversations#

GET/api/v1/conversations

Requires inbox:read. Reply and mention conversations across the workspace's connected accounts, newest first. ?postId= scopes to one published post row (for an in-composer replies panel) and ?groupId= to a post by its composer group across every channel — one or the other, not both; ?type= selects replies vs mentions, omit it for both. Reads the local store — call POST /conversations/sync to refresh from the platforms. Rows past their platform's retention window (LinkedIn member content) are re-read from the platform first, waiting a few seconds at most; contentExpired stays true on any that couldn't be.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Query parameters

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

statusstring
  • "open"
  • "resolved"
  • "snoozed"
platformstring
  • "bluesky"
  • "twitter"
  • "threads"
  • "mastodon"
  • "facebook_page"
  • "instagram"
  • "linkedin_page"
typestring
  • "reply"
  • "mention"
postIdstring

Conversations under one published post row — the postId on a GET /posts entry or in GET /analytics/results, not the post's groupId. For that, pass groupId.

groupIdstring

Conversations under a post by its composer group (the id GET /posts and GET /posts/draft use), across every channel it went out on. Not alongside postId.

accountIdstring
assigneestring

Ownership scope: me (session caller's own), unassigned, or a userId

inboxIdstring

Scope to one team inbox (Inbox 2.0)

cursorstring
limitinteger

Between 1 and 100.

Responses

200ConversationList

A page of conversations

Response attributes
conversationsConversationSummary[]Required
Child attributes
idstringRequired
platformstringRequired

Platform id, e.g. "bluesky"

accountIdstringRequired
typestringRequired
  • "reply"
  • "mention"
statusstringRequired
  • "open"
  • "resolved"
  • "snoozed"
participantConversationParticipantRequired
Child attributes
handlestringRequired
displayNamestringRequired
avatarUrlstring | nullRequired
lastMessagePreviewstringRequired
lastMediaKindstring | nullRequired

Media kind of the latest reply for a list glyph; null if text-only

  • "image"
  • "gif"
  • "video"
  • null
lastMessageAtstring | nullRequired

ISO 8601

unreadbooleanRequired
snoozedUntilstring | nullRequired

ISO 8601 wake time when status is "snoozed"; null otherwise

assigneeUserIdstring | nullRequired

User id of the teammate who owns this conversation; null when unassigned

contentExpiredbooleanRequired

The participant or preview has passed the platform's retention window (LinkedIn caches member profiles for 24 hours and keeps member posts and comments for 48) and been dropped. The list and detail reads re-fetch them when they can.

nextCursorstring | nullRequired

Pass as cursor to fetch the next page; null when exhausted

400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
GET /api/v1/conversations
curl -X GET "https://orbitwrite.com/api/v1/conversations" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "conversations": [
    {
      "id": "string",
      "platform": "string",
      "accountId": "string",
      "type": "reply",
      "status": "open",
      "participant": {
        "handle": "string",
        "displayName": "string",
        "avatarUrl": "string"
      },
      "lastMessagePreview": "string",
      "lastMediaKind": "image",
      "lastMessageAt": "string",
      "unread": true,
      "snoozedUntil": "string",
      "assigneeUserId": "string",
      "contentExpired": true
    }
  ],
  "nextCursor": "string"
}

Count the conversations in a view#

GET/api/v1/conversations/count

Requires inbox:read. How many conversations a view holds — what the inbox's badges show. It takes the same filters as GET /conversations (type, assignee, inboxId, platform, accountId, postId or groupId), so a badge counts exactly what selecting that view lists, plus status (open by default). unread=true narrows to conversations whose latest activity is an incoming message nobody has read yet — what the app's sidebar badge counts, which is a different question from how much is still open. A session caller that names no organizationId falls back to its active workspace, reading 0 when it has none.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Query parameters

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

platformstring
  • "bluesky"
  • "twitter"
  • "threads"
  • "mastodon"
  • "facebook_page"
  • "instagram"
  • "linkedin_page"
typestring
  • "reply"
  • "mention"
postIdstring

Conversations under one published post row — the postId on a GET /posts entry or in GET /analytics/results, not the post's groupId. For that, pass groupId.

groupIdstring

Conversations under a post by its composer group (the id GET /posts and GET /posts/draft use), across every channel it went out on. Not alongside postId.

accountIdstring
assigneestring

Ownership scope: me (session caller's own), unassigned, or a userId

inboxIdstring

Scope to one team inbox (Inbox 2.0)

statusstring
  • "open"
  • "resolved"
  • "snoozed"
unreadstring

Only conversations with unread incoming activity

  • "true"
  • "false"

Responses

200object

The count

Response attributes
countintegerRequired
400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
GET /api/v1/conversations/count
curl -X GET "https://orbitwrite.com/api/v1/conversations/count" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "count": 0
}

Pull fresh replies from the platforms#

POST/api/v1/conversations/sync

Requires inbox:update — a sync writes the shared store and spends the platforms' metered read budget. Ingests replies for the workspace's in-scope published posts (X/Threads/Bluesky) through the platform adapters into the inbox store. Backs the "Sync now" button and the on-open refresh. Idempotent — re-running only inserts genuinely new replies. Skipped (with skipped: true) when a sync ran within the last 2 minutes, unless force is set. Each account is also polled no more often than its platform's cadence allows (notDue counts the ones left out; force polls them anyway), and a platform that has rate-limited us is left alone until its reset, even under force (throttled). Forced syncs are rate limited per credential.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Body application/json

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

forceboolean

Bypass the recent-sync cooldown (used by the explicit "Sync now" button)

Responses

200InboxSyncResult

Sync summary

Response attributes
fetchedintegerRequired
insertedintegerRequired
perPlatformobjectRequired
errorsobject[]Required
Child attributes
platformstringRequired
accountIdstringRequired
messagestringRequired
throttledobject[]

Steps a platform is rate-limiting right now, and until when. GET /conversations/sync-status reads the same state.

Child attributes
platformstringRequired
accountIdstringRequired
stepstringRequired
untilstringRequired

ISO instant the platform will be asked again

notDueinteger

Accounts left out because their poll cadence isn't due yet; pass force to poll them anyway

skippedboolean

True when the sync was skipped because one ran within the cooldown window; pass force to override

400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
429Error

Rate limit exceeded

Response attributes
errorstringRequired
issuesany[]
POST /api/v1/conversations/sync
curl -X POST "https://orbitwrite.com/api/v1/conversations/sync" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "organizationId": "string",
  "force": true
}'
Response
{
  "fetched": 0,
  "inserted": 0,
  "perPlatform": {},
  "errors": [
    {
      "platform": "string",
      "accountId": "string",
      "message": "string"
    }
  ],
  "throttled": [
    {
      "platform": "string",
      "accountId": "string",
      "step": "string",
      "until": "string"
    }
  ],
  "notDue": 0,
  "skipped": true
}

Where each channel's inbox polling stands#

GET/api/v1/conversations/sync-status

Requires inbox:read. One entry per connected channel that has an inbox: when it was last pulled, the schedule the worker keeps (mode, pollIntervalSec, nextPollAt) and any steps the platform is rate-limiting right now (throttles, each with the instant it will be asked again). A platform that has rate-limited the application is left alone until its reset, even by a forced sync, so this is how to tell a quiet inbox from a paused one.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Query parameters

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

Responses

200object

Per-channel polling status

Response attributes
accountsInboxSyncStatus[]Required
Child attributes
accountIdstringRequired
platformstringRequired
displayHandlestring | nullRequired
needsReconnectbooleanRequired

The channel needs reconnecting, so it is not being polled at all

lastPolledAtstring | nullRequired
modestringRequired

Active while something moved in the last day, else idle (polled more slowly)

  • "active"
  • "idle"
pollIntervalSecintegerRequired

The gap between unforced polls in the current mode

nextPollAtstring | nullRequired

The earliest the next unforced poll runs. Null when the channel has never been polled or is paused for a reconnect

throttlesobject[]Required
Child attributes
stepstringRequired
  • "activity"
  • "mentions"
  • "discovery"
  • "replies"
  • "context"
untilstringRequired

ISO instant the platform will be asked again

reasonstringRequired
400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
GET /api/v1/conversations/sync-status
curl -X GET "https://orbitwrite.com/api/v1/conversations/sync-status" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "accounts": [
    {
      "accountId": "string",
      "platform": "string",
      "displayHandle": "string",
      "needsReconnect": true,
      "lastPolledAt": "string",
      "mode": "active",
      "pollIntervalSec": 0,
      "nextPollAt": "string",
      "throttles": [
        {
          "step": "activity",
          "until": "string",
          "reason": "string"
        }
      ]
    }
  ]
}

Bulk resolve or reopen conversations#

POST/api/v1/conversations/mark-all

Requires inbox:update. Flips every conversation currently in from to to for the workspace — backs the list's "Resolve all / Reopen all" action. type, platform, postId or groupId, accountId, assignee and inboxId scope the sweep exactly as they scope GET /conversations, so pass the filters of the view the sweep fires from; omit them all to sweep the whole workspace.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Body application/json

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

fromstringRequired
  • "open"
  • "resolved"
  • "snoozed"
platformstring
  • "bluesky"
  • "twitter"
  • "threads"
  • "mastodon"
  • "facebook_page"
  • "instagram"
  • "linkedin_page"
typestring
  • "reply"
  • "mention"
postIdstring

Conversations under one published post row — the postId on a GET /posts entry or in GET /analytics/results, not the post's groupId. For that, pass groupId.

groupIdstring

Conversations under a post by its composer group (the id GET /posts and GET /posts/draft use), across every channel it went out on. Not alongside postId.

accountIdstring
assigneestring

Ownership scope: me (session caller's own), unassigned, or a userId

inboxIdstring

Scope to one team inbox (Inbox 2.0)

tostringRequired
  • "open"
  • "resolved"

Responses

200object

How many conversations changed

Response attributes
countintegerRequired
400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
POST /api/v1/conversations/mark-all
curl -X POST "https://orbitwrite.com/api/v1/conversations/mark-all" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "from": "open",
  "to": "open"
}'
Response
{
  "count": 0
}

Bulk snooze conversations#

POST/api/v1/conversations/snooze-all

Requires inbox:update. Snoozes every conversation currently in from until until, moving them to the shared "snoozed" category — backs the list's "Snooze all" action. A background sweep returns each to the open list (as unread) when that time passes. type, platform, postId or groupId, accountId, assignee and inboxId scope the sweep exactly as they scope GET /conversations; omit them all to sweep the whole workspace.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Body application/json

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

fromstringRequired
  • "open"
  • "resolved"
  • "snoozed"
platformstring
  • "bluesky"
  • "twitter"
  • "threads"
  • "mastodon"
  • "facebook_page"
  • "instagram"
  • "linkedin_page"
typestring
  • "reply"
  • "mention"
postIdstring

Conversations under one published post row — the postId on a GET /posts entry or in GET /analytics/results, not the post's groupId. For that, pass groupId.

groupIdstring

Conversations under a post by its composer group (the id GET /posts and GET /posts/draft use), across every channel it went out on. Not alongside postId.

accountIdstring
assigneestring

Ownership scope: me (session caller's own), unassigned, or a userId

inboxIdstring

Scope to one team inbox (Inbox 2.0)

untilstringRequired

ISO 8601 wake time; must be in the future

Format date-time.

Responses

200object

How many conversations changed

Response attributes
countintegerRequired
400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
POST /api/v1/conversations/snooze-all
curl -X POST "https://orbitwrite.com/api/v1/conversations/snooze-all" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "from": "open",
  "until": "2026-10-01T09:00:00Z"
}'
Response
{
  "count": 0
}

List replies held for approval#

GET/api/v1/conversations/pending-replies

Requires approval:read. The reply-approval lane (Inbox 2.0): replies a gated member drafted that are waiting on an approval:decide holder. ?mine=true scopes to the caller's own held replies (their pending / rejected / failed) — the drafter's view; omit it for the whole workspace (the deciders' queue). ?status= narrows to one state.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Query parameters

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

minestring

Scope to the caller's own held replies

  • "true"
  • "false"
statusstring
  • "pending"
  • "approved"
  • "rejected"
  • "sent"
  • "failed"

Responses

200object

The held replies

Response attributes
pendingRepliesPendingReplySummary[]Required
Child attributes
idstringRequired
conversationIdstringRequired
organizationIdstringRequired
statusstringRequired
  • "pending"
  • "approved"
  • "rejected"
  • "sent"
  • "failed"
bodystringRequired
mediaPendingReplyMedia[]Required
Child attributes
urlstringRequired
mimeTypestringRequired
altTextstring
sourceUrlstring
videoUrlstring
widthnumber
heightnumber
bytesnumber
replyToMessageIdstring | nullRequired
decisionNotestring | nullRequired
sendErrorstring | nullRequired

Why the platform send failed, for a failed reply

createdAtstringRequired

ISO 8601

decidedAtstring | nullRequired

ISO 8601

decidablebooleanRequired

Whether an approval:decide holder can act on it now: pending, failed, or approved with a send that never finished (retryable after 10 minutes)

draftedByPendingReplyUserRequired
Child attributes
idstringRequired
namestringRequired
avatarUrlstring | nullRequired
decidedByPendingReplyUser | any | nullRequired
Child attributes
idstringRequired
namestringRequired
avatarUrlstring | nullRequired
conversationobjectRequired
Child attributes
platformstringRequired
participantHandlestringRequired
400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
GET /api/v1/conversations/pending-replies
curl -X GET "https://orbitwrite.com/api/v1/conversations/pending-replies" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "pendingReplies": [
    {
      "id": "string",
      "conversationId": "string",
      "organizationId": "string",
      "status": "pending",
      "body": "string",
      "media": [
        {
          "url": "string",
          "mimeType": "string",
          "altText": "string",
          "sourceUrl": "string",
          "videoUrl": "string",
          "width": 0,
          "height": 0,
          "bytes": 0
        }
      ],
      "replyToMessageId": "string",
      "decisionNote": "string",
      "sendError": "string",
      "createdAt": "string",
      "decidedAt": "string",
      "decidable": true,
      "draftedBy": {
        "id": "string",
        "name": "string",
        "avatarUrl": "string"
      },
      "decidedBy": {
        "id": "string",
        "name": "string",
        "avatarUrl": "string"
      },
      "conversation": {
        "platform": "string",
        "participantHandle": "string",
        "participantDisplayName": "string"
      }
    }
  ]
}

Approve, edit & approve, or reject a held reply#

POST/api/v1/conversations/pending-replies/{pendingReplyId}/decide

Requires approval:decide. approve sends the drafted reply as-is; edit_approve sends body instead; reject records note back to the drafter and sends nothing. Approving publishes through the platform — a send that fails after approval returns 502 with the reply in failed, retryable by deciding again (as is an approval whose send never finished, once decidable turns true). A decider can't approve a reply attributed to themselves unless they could have sent it directly (inbox:reply). Approvals are rate limited per credential; rejections are not.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Path parameters

pendingReplyIdstringRequired

At least 1 character.

Body application/json

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

actionstringRequired
  • "approve"
  • "edit_approve"
  • "reject"
bodystring

Replacement text for edit_approve

notestring

A note back to the drafter (the reject reason)

Responses

200object

The decided reply

Response attributes
pendingReplyPendingReplySummaryRequired
Child attributes
idstringRequired
conversationIdstringRequired
organizationIdstringRequired
statusstringRequired
  • "pending"
  • "approved"
  • "rejected"
  • "sent"
  • "failed"
bodystringRequired
mediaPendingReplyMedia[]Required
Child attributes
urlstringRequired
mimeTypestringRequired
altTextstring
sourceUrlstring
videoUrlstring
widthnumber
heightnumber
bytesnumber
replyToMessageIdstring | nullRequired
decisionNotestring | nullRequired
sendErrorstring | nullRequired

Why the platform send failed, for a failed reply

createdAtstringRequired

ISO 8601

decidedAtstring | nullRequired

ISO 8601

decidablebooleanRequired

Whether an approval:decide holder can act on it now: pending, failed, or approved with a send that never finished (retryable after 10 minutes)

draftedByPendingReplyUserRequired
Child attributes
idstringRequired
namestringRequired
avatarUrlstring | nullRequired
decidedByPendingReplyUser | any | nullRequired
Child attributes
idstringRequired
namestringRequired
avatarUrlstring | nullRequired
conversationobjectRequired
Child attributes
platformstringRequired
participantHandlestringRequired
400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
404Error

The resource does not exist

Response attributes
errorstringRequired
issuesany[]
409object

Already decided by someone else

Response attributes
errorstringRequired
429Error

Rate limit exceeded

Response attributes
errorstringRequired
issuesany[]
502object

Approved, but the platform rejected the send (retryable)

Response attributes
errorstringRequired
pendingReplyPendingReplySummaryRequired
Child attributes
idstringRequired
conversationIdstringRequired
organizationIdstringRequired
statusstringRequired
  • "pending"
  • "approved"
  • "rejected"
  • "sent"
  • "failed"
bodystringRequired
mediaPendingReplyMedia[]Required
Child attributes
urlstringRequired
mimeTypestringRequired
altTextstring
sourceUrlstring
videoUrlstring
widthnumber
heightnumber
bytesnumber
replyToMessageIdstring | nullRequired
decisionNotestring | nullRequired
sendErrorstring | nullRequired

Why the platform send failed, for a failed reply

createdAtstringRequired

ISO 8601

decidedAtstring | nullRequired

ISO 8601

decidablebooleanRequired

Whether an approval:decide holder can act on it now: pending, failed, or approved with a send that never finished (retryable after 10 minutes)

draftedByPendingReplyUserRequired
Child attributes
idstringRequired
namestringRequired
avatarUrlstring | nullRequired
decidedByPendingReplyUser | any | nullRequired
Child attributes
idstringRequired
namestringRequired
avatarUrlstring | nullRequired
conversationobjectRequired
Child attributes
platformstringRequired
participantHandlestringRequired
POST /api/v1/conversations/pending-replies/{pendingReplyId}/decide
curl -X POST "https://orbitwrite.com/api/v1/conversations/pending-replies/{pendingReplyId}/decide" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "action": "approve"
}'
Response
{
  "pendingReply": {
    "id": "string",
    "conversationId": "string",
    "organizationId": "string",
    "status": "pending",
    "body": "string",
    "media": [
      {
        "url": "string",
        "mimeType": "string",
        "altText": "string",
        "sourceUrl": "string",
        "videoUrl": "string",
        "width": 0,
        "height": 0,
        "bytes": 0
      }
    ],
    "replyToMessageId": "string",
    "decisionNote": "string",
    "sendError": "string",
    "createdAt": "string",
    "decidedAt": "string",
    "decidable": true,
    "draftedBy": {
      "id": "string",
      "name": "string",
      "avatarUrl": "string"
    },
    "decidedBy": {
      "id": "string",
      "name": "string",
      "avatarUrl": "string"
    },
    "conversation": {
      "platform": "string",
      "participantHandle": "string",
      "participantDisplayName": "string"
    }
  }
}

Pull the next waiting conversation to yourself#

POST/api/v1/conversations/pull

Requires a signed-in user and inbox:update. Assigns the oldest unassigned open conversation (optionally within one team inbox) to the caller, ignoring capacity and away by design. Returns { pulled: null } when nothing is waiting. A workspace API key has no one to assign to — use POST /conversations/{conversationId}/assign.

Authentication

A signed-in session only. The Orbitwrite app calls this; an API key is refused.

Body application/json

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

inboxIdstring

At least 1 character.

Responses

200object

The claimed conversation, or null when none waiting

Response attributes
pulledConversationDetail | any | nullRequired
Child attributes
idstringRequired
platformstringRequired

Platform id, e.g. "bluesky"

accountIdstringRequired
typestringRequired
  • "reply"
  • "mention"
statusstringRequired
  • "open"
  • "resolved"
  • "snoozed"
participantConversationParticipantRequired
Child attributes
handlestringRequired
displayNamestringRequired
avatarUrlstring | nullRequired
lastMessagePreviewstringRequired
lastMediaKindstring | nullRequired

Media kind of the latest reply for a list glyph; null if text-only

  • "image"
  • "gif"
  • "video"
  • null
lastMessageAtstring | nullRequired

ISO 8601

unreadbooleanRequired
snoozedUntilstring | nullRequired

ISO 8601 wake time when status is "snoozed"; null otherwise

assigneeUserIdstring | nullRequired

User id of the teammate who owns this conversation; null when unassigned

contentExpiredbooleanRequired

The participant or preview has passed the platform's retention window (LinkedIn caches member profiles for 24 hours and keeps member posts and comments for 48) and been dropped. The list and detail reads re-fetch them when they can.

originalPostobject | nullRequired

The published post being replied to, pinned on top

Child attributes
idstringRequired

The post row this conversation hangs off (the inbox's postId), or the platform's own id for a native post.

groupIdstring | nullRequired

The post's composer group — what GET /posts/draft, score and schedule take. Null for a post not published through Orbitwrite.

textstringRequired
platformUrlstring | nullRequired
platformPostIdstring | nullRequired
authorobjectRequired
Child attributes
handlestringRequired
avatarUrlstring | nullRequired
createdAtstring | nullRequired
messagesConversationMessage[]Required
Child attributes
idstringRequired
directionstringRequired
  • "in"
  • "out"
authorConversationParticipantRequired
Child attributes
handlestringRequired
displayNamestringRequired
avatarUrlstring | nullRequired
textstringRequired
mediaConversationMedia[]Required

Images / GIFs / video attached to the message

Child attributes
kindstringRequired
  • "image"
  • "gif"
  • "video"
urlstringRequired

Displayable URL (image, GIF, or video poster)

videoUrlstring | null

Playable video source (for video, and an mp4 alt for a GIF)

altTextstring | null
widthnumber | null
heightnumber | null
permalinkUrlstring | nullRequired
createdAtstring | nullRequired

ISO 8601

platformReplyIdstring | nullRequired

Remote id of this reply — the target when replying to it

parentPlatformIdstring | nullRequired

Remote id of the post/reply this one replies to (thread structure)

contentExpiredbooleanRequired

The text, media or author has passed the platform's retention window and been dropped; the detail read re-fetches them when it can.

textExpiredbooleanRequired

Narrower than contentExpired: the text and media themselves have passed the retention window (LinkedIn: 48 hours), rather than only the author's profile (24 hours). An empty text with this false means the platform never supplied any.

400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
POST /api/v1/conversations/pull
curl -X POST "https://orbitwrite.com/api/v1/conversations/pull" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "organizationId": "string",
  "inboxId": "string"
}'
Response
{
  "pulled": {
    "id": "string",
    "platform": "string",
    "accountId": "string",
    "type": "reply",
    "status": "open",
    "participant": {
      "handle": "string",
      "displayName": "string",
      "avatarUrl": "string"
    },
    "lastMessagePreview": "string",
    "lastMediaKind": "image",
    "lastMessageAt": "string",
    "unread": true,
    "snoozedUntil": "string",
    "assigneeUserId": "string",
    "contentExpired": true,
    "originalPost": {
      "id": "string",
      "groupId": "string",
      "text": "string",
      "platformUrl": "string",
      "platformPostId": "string",
      "author": {
        "handle": "string",
        "avatarUrl": "string"
      },
      "createdAt": "string"
    },
    "messages": [
      {
        "id": "string",
        "direction": "in",
        "author": {
          "handle": "string",
          "displayName": "string",
          "avatarUrl": "string"
        },
        "text": "string",
        "media": [
          {
            "kind": "image",
            "url": "string",
            "videoUrl": "string",
            "altText": "string",
            "width": 0,
            "height": 0
          }
        ],
        "permalinkUrl": "string",
        "createdAt": "string",
        "platformReplyId": "string",
        "parentPlatformId": "string",
        "contentExpired": true,
        "textExpired": true
      }
    ]
  }
}

Get one conversation with its thread#

GET/api/v1/conversations/{conversationId}

Requires inbox:read. The conversation, the original published post pinned on top, and every message (incoming replies and our outbound answers) in chronological order.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Path parameters

conversationIdstringRequired

At least 1 character.

Query parameters

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

Responses

200ConversationDetail

The conversation detail

Response attributes
idstringRequired
platformstringRequired

Platform id, e.g. "bluesky"

accountIdstringRequired
typestringRequired
  • "reply"
  • "mention"
statusstringRequired
  • "open"
  • "resolved"
  • "snoozed"
participantConversationParticipantRequired
Child attributes
handlestringRequired
displayNamestringRequired
avatarUrlstring | nullRequired
lastMessagePreviewstringRequired
lastMediaKindstring | nullRequired

Media kind of the latest reply for a list glyph; null if text-only

  • "image"
  • "gif"
  • "video"
  • null
lastMessageAtstring | nullRequired

ISO 8601

unreadbooleanRequired
snoozedUntilstring | nullRequired

ISO 8601 wake time when status is "snoozed"; null otherwise

assigneeUserIdstring | nullRequired

User id of the teammate who owns this conversation; null when unassigned

contentExpiredbooleanRequired

The participant or preview has passed the platform's retention window (LinkedIn caches member profiles for 24 hours and keeps member posts and comments for 48) and been dropped. The list and detail reads re-fetch them when they can.

originalPostobject | nullRequired

The published post being replied to, pinned on top

Child attributes
idstringRequired

The post row this conversation hangs off (the inbox's postId), or the platform's own id for a native post.

groupIdstring | nullRequired

The post's composer group — what GET /posts/draft, score and schedule take. Null for a post not published through Orbitwrite.

textstringRequired
platformUrlstring | nullRequired
platformPostIdstring | nullRequired
authorobjectRequired
Child attributes
handlestringRequired
avatarUrlstring | nullRequired
createdAtstring | nullRequired
messagesConversationMessage[]Required
Child attributes
idstringRequired
directionstringRequired
  • "in"
  • "out"
authorConversationParticipantRequired
Child attributes
handlestringRequired
displayNamestringRequired
avatarUrlstring | nullRequired
textstringRequired
mediaConversationMedia[]Required

Images / GIFs / video attached to the message

Child attributes
kindstringRequired
  • "image"
  • "gif"
  • "video"
urlstringRequired

Displayable URL (image, GIF, or video poster)

videoUrlstring | null

Playable video source (for video, and an mp4 alt for a GIF)

altTextstring | null
widthnumber | null
heightnumber | null
permalinkUrlstring | nullRequired
createdAtstring | nullRequired

ISO 8601

platformReplyIdstring | nullRequired

Remote id of this reply — the target when replying to it

parentPlatformIdstring | nullRequired

Remote id of the post/reply this one replies to (thread structure)

contentExpiredbooleanRequired

The text, media or author has passed the platform's retention window and been dropped; the detail read re-fetches them when it can.

textExpiredbooleanRequired

Narrower than contentExpired: the text and media themselves have passed the retention window (LinkedIn: 48 hours), rather than only the author's profile (24 hours). An empty text with this false means the platform never supplied any.

400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
404Error

The resource does not exist

Response attributes
errorstringRequired
issuesany[]
GET /api/v1/conversations/{conversationId}
curl -X GET "https://orbitwrite.com/api/v1/conversations/{conversationId}" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY"
Response
{
  "id": "string",
  "platform": "string",
  "accountId": "string",
  "type": "reply",
  "status": "open",
  "participant": {
    "handle": "string",
    "displayName": "string",
    "avatarUrl": "string"
  },
  "lastMessagePreview": "string",
  "lastMediaKind": "image",
  "lastMessageAt": "string",
  "unread": true,
  "snoozedUntil": "string",
  "assigneeUserId": "string",
  "contentExpired": true,
  "originalPost": {
    "id": "string",
    "groupId": "string",
    "text": "string",
    "platformUrl": "string",
    "platformPostId": "string",
    "author": {
      "handle": "string",
      "avatarUrl": "string"
    },
    "createdAt": "string"
  },
  "messages": [
    {
      "id": "string",
      "direction": "in",
      "author": {
        "handle": "string",
        "displayName": "string",
        "avatarUrl": "string"
      },
      "text": "string",
      "media": [
        {
          "kind": "image",
          "url": "string",
          "videoUrl": "string",
          "altText": "string",
          "width": 0,
          "height": 0
        }
      ],
      "permalinkUrl": "string",
      "createdAt": "string",
      "platformReplyId": "string",
      "parentPlatformId": "string",
      "contentExpired": true,
      "textExpired": true
    }
  ]
}

Resolve or reopen a conversation#

PATCH/api/v1/conversations/{conversationId}

Requires inbox:update. Flips the conversation's shared status. Resolving moves it out of the open list into the resolved category for the whole workspace.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Path parameters

conversationIdstringRequired

At least 1 character.

Body application/json

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

statusstringRequired
  • "open"
  • "resolved"

Responses

200ConversationDetail

The updated conversation

Response attributes
idstringRequired
platformstringRequired

Platform id, e.g. "bluesky"

accountIdstringRequired
typestringRequired
  • "reply"
  • "mention"
statusstringRequired
  • "open"
  • "resolved"
  • "snoozed"
participantConversationParticipantRequired
Child attributes
handlestringRequired
displayNamestringRequired
avatarUrlstring | nullRequired
lastMessagePreviewstringRequired
lastMediaKindstring | nullRequired

Media kind of the latest reply for a list glyph; null if text-only

  • "image"
  • "gif"
  • "video"
  • null
lastMessageAtstring | nullRequired

ISO 8601

unreadbooleanRequired
snoozedUntilstring | nullRequired

ISO 8601 wake time when status is "snoozed"; null otherwise

assigneeUserIdstring | nullRequired

User id of the teammate who owns this conversation; null when unassigned

contentExpiredbooleanRequired

The participant or preview has passed the platform's retention window (LinkedIn caches member profiles for 24 hours and keeps member posts and comments for 48) and been dropped. The list and detail reads re-fetch them when they can.

originalPostobject | nullRequired

The published post being replied to, pinned on top

Child attributes
idstringRequired

The post row this conversation hangs off (the inbox's postId), or the platform's own id for a native post.

groupIdstring | nullRequired

The post's composer group — what GET /posts/draft, score and schedule take. Null for a post not published through Orbitwrite.

textstringRequired
platformUrlstring | nullRequired
platformPostIdstring | nullRequired
authorobjectRequired
Child attributes
handlestringRequired
avatarUrlstring | nullRequired
createdAtstring | nullRequired
messagesConversationMessage[]Required
Child attributes
idstringRequired
directionstringRequired
  • "in"
  • "out"
authorConversationParticipantRequired
Child attributes
handlestringRequired
displayNamestringRequired
avatarUrlstring | nullRequired
textstringRequired
mediaConversationMedia[]Required

Images / GIFs / video attached to the message

Child attributes
kindstringRequired
  • "image"
  • "gif"
  • "video"
urlstringRequired

Displayable URL (image, GIF, or video poster)

videoUrlstring | null

Playable video source (for video, and an mp4 alt for a GIF)

altTextstring | null
widthnumber | null
heightnumber | null
permalinkUrlstring | nullRequired
createdAtstring | nullRequired

ISO 8601

platformReplyIdstring | nullRequired

Remote id of this reply — the target when replying to it

parentPlatformIdstring | nullRequired

Remote id of the post/reply this one replies to (thread structure)

contentExpiredbooleanRequired

The text, media or author has passed the platform's retention window and been dropped; the detail read re-fetches them when it can.

textExpiredbooleanRequired

Narrower than contentExpired: the text and media themselves have passed the retention window (LinkedIn: 48 hours), rather than only the author's profile (24 hours). An empty text with this false means the platform never supplied any.

400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
404Error

The resource does not exist

Response attributes
errorstringRequired
issuesany[]
PATCH /api/v1/conversations/{conversationId}
curl -X PATCH "https://orbitwrite.com/api/v1/conversations/{conversationId}" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "open"
}'
Response
{
  "id": "string",
  "platform": "string",
  "accountId": "string",
  "type": "reply",
  "status": "open",
  "participant": {
    "handle": "string",
    "displayName": "string",
    "avatarUrl": "string"
  },
  "lastMessagePreview": "string",
  "lastMediaKind": "image",
  "lastMessageAt": "string",
  "unread": true,
  "snoozedUntil": "string",
  "assigneeUserId": "string",
  "contentExpired": true,
  "originalPost": {
    "id": "string",
    "groupId": "string",
    "text": "string",
    "platformUrl": "string",
    "platformPostId": "string",
    "author": {
      "handle": "string",
      "avatarUrl": "string"
    },
    "createdAt": "string"
  },
  "messages": [
    {
      "id": "string",
      "direction": "in",
      "author": {
        "handle": "string",
        "displayName": "string",
        "avatarUrl": "string"
      },
      "text": "string",
      "media": [
        {
          "kind": "image",
          "url": "string",
          "videoUrl": "string",
          "altText": "string",
          "width": 0,
          "height": 0
        }
      ],
      "permalinkUrl": "string",
      "createdAt": "string",
      "platformReplyId": "string",
      "parentPlatformId": "string",
      "contentExpired": true,
      "textExpired": true
    }
  ]
}

Assign, reassign, or unassign a conversation#

POST/api/v1/conversations/{conversationId}/assign

Requires inbox:update. Sets the teammate who owns this conversation, or pass assigneeUserId: null to return it to the shared/unassigned pool. Ownership is shared workspace state (every role can assign), and the change is audited. A non-null assignee must be a member of the workspace.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Path parameters

conversationIdstringRequired

At least 1 character.

Body application/json

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

assigneeUserIdstring | nullRequired

The teammate to own this conversation, or null to unassign

At least 1 character.

Responses

200ConversationDetail

The updated conversation

Response attributes
idstringRequired
platformstringRequired

Platform id, e.g. "bluesky"

accountIdstringRequired
typestringRequired
  • "reply"
  • "mention"
statusstringRequired
  • "open"
  • "resolved"
  • "snoozed"
participantConversationParticipantRequired
Child attributes
handlestringRequired
displayNamestringRequired
avatarUrlstring | nullRequired
lastMessagePreviewstringRequired
lastMediaKindstring | nullRequired

Media kind of the latest reply for a list glyph; null if text-only

  • "image"
  • "gif"
  • "video"
  • null
lastMessageAtstring | nullRequired

ISO 8601

unreadbooleanRequired
snoozedUntilstring | nullRequired

ISO 8601 wake time when status is "snoozed"; null otherwise

assigneeUserIdstring | nullRequired

User id of the teammate who owns this conversation; null when unassigned

contentExpiredbooleanRequired

The participant or preview has passed the platform's retention window (LinkedIn caches member profiles for 24 hours and keeps member posts and comments for 48) and been dropped. The list and detail reads re-fetch them when they can.

originalPostobject | nullRequired

The published post being replied to, pinned on top

Child attributes
idstringRequired

The post row this conversation hangs off (the inbox's postId), or the platform's own id for a native post.

groupIdstring | nullRequired

The post's composer group — what GET /posts/draft, score and schedule take. Null for a post not published through Orbitwrite.

textstringRequired
platformUrlstring | nullRequired
platformPostIdstring | nullRequired
authorobjectRequired
Child attributes
handlestringRequired
avatarUrlstring | nullRequired
createdAtstring | nullRequired
messagesConversationMessage[]Required
Child attributes
idstringRequired
directionstringRequired
  • "in"
  • "out"
authorConversationParticipantRequired
Child attributes
handlestringRequired
displayNamestringRequired
avatarUrlstring | nullRequired
textstringRequired
mediaConversationMedia[]Required

Images / GIFs / video attached to the message

Child attributes
kindstringRequired
  • "image"
  • "gif"
  • "video"
urlstringRequired

Displayable URL (image, GIF, or video poster)

videoUrlstring | null

Playable video source (for video, and an mp4 alt for a GIF)

altTextstring | null
widthnumber | null
heightnumber | null
permalinkUrlstring | nullRequired
createdAtstring | nullRequired

ISO 8601

platformReplyIdstring | nullRequired

Remote id of this reply — the target when replying to it

parentPlatformIdstring | nullRequired

Remote id of the post/reply this one replies to (thread structure)

contentExpiredbooleanRequired

The text, media or author has passed the platform's retention window and been dropped; the detail read re-fetches them when it can.

textExpiredbooleanRequired

Narrower than contentExpired: the text and media themselves have passed the retention window (LinkedIn: 48 hours), rather than only the author's profile (24 hours). An empty text with this false means the platform never supplied any.

400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
404Error

The resource does not exist

Response attributes
errorstringRequired
issuesany[]
POST /api/v1/conversations/{conversationId}/assign
curl -X POST "https://orbitwrite.com/api/v1/conversations/{conversationId}/assign" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "assigneeUserId": "string"
}'
Response
{
  "id": "string",
  "platform": "string",
  "accountId": "string",
  "type": "reply",
  "status": "open",
  "participant": {
    "handle": "string",
    "displayName": "string",
    "avatarUrl": "string"
  },
  "lastMessagePreview": "string",
  "lastMediaKind": "image",
  "lastMessageAt": "string",
  "unread": true,
  "snoozedUntil": "string",
  "assigneeUserId": "string",
  "contentExpired": true,
  "originalPost": {
    "id": "string",
    "groupId": "string",
    "text": "string",
    "platformUrl": "string",
    "platformPostId": "string",
    "author": {
      "handle": "string",
      "avatarUrl": "string"
    },
    "createdAt": "string"
  },
  "messages": [
    {
      "id": "string",
      "direction": "in",
      "author": {
        "handle": "string",
        "displayName": "string",
        "avatarUrl": "string"
      },
      "text": "string",
      "media": [
        {
          "kind": "image",
          "url": "string",
          "videoUrl": "string",
          "altText": "string",
          "width": 0,
          "height": 0
        }
      ],
      "permalinkUrl": "string",
      "createdAt": "string",
      "platformReplyId": "string",
      "parentPlatformId": "string",
      "contentExpired": true,
      "textExpired": true
    }
  ]
}

Mark a conversation read#

POST/api/v1/conversations/{conversationId}/read

Requires inbox:update. Advances the shared read watermark to now, clearing the unread indicator for the whole workspace.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Path parameters

conversationIdstringRequired

At least 1 character.

Body application/json

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

Responses

200ConversationDetail

The updated conversation

Response attributes
idstringRequired
platformstringRequired

Platform id, e.g. "bluesky"

accountIdstringRequired
typestringRequired
  • "reply"
  • "mention"
statusstringRequired
  • "open"
  • "resolved"
  • "snoozed"
participantConversationParticipantRequired
Child attributes
handlestringRequired
displayNamestringRequired
avatarUrlstring | nullRequired
lastMessagePreviewstringRequired
lastMediaKindstring | nullRequired

Media kind of the latest reply for a list glyph; null if text-only

  • "image"
  • "gif"
  • "video"
  • null
lastMessageAtstring | nullRequired

ISO 8601

unreadbooleanRequired
snoozedUntilstring | nullRequired

ISO 8601 wake time when status is "snoozed"; null otherwise

assigneeUserIdstring | nullRequired

User id of the teammate who owns this conversation; null when unassigned

contentExpiredbooleanRequired

The participant or preview has passed the platform's retention window (LinkedIn caches member profiles for 24 hours and keeps member posts and comments for 48) and been dropped. The list and detail reads re-fetch them when they can.

originalPostobject | nullRequired

The published post being replied to, pinned on top

Child attributes
idstringRequired

The post row this conversation hangs off (the inbox's postId), or the platform's own id for a native post.

groupIdstring | nullRequired

The post's composer group — what GET /posts/draft, score and schedule take. Null for a post not published through Orbitwrite.

textstringRequired
platformUrlstring | nullRequired
platformPostIdstring | nullRequired
authorobjectRequired
Child attributes
handlestringRequired
avatarUrlstring | nullRequired
createdAtstring | nullRequired
messagesConversationMessage[]Required
Child attributes
idstringRequired
directionstringRequired
  • "in"
  • "out"
authorConversationParticipantRequired
Child attributes
handlestringRequired
displayNamestringRequired
avatarUrlstring | nullRequired
textstringRequired
mediaConversationMedia[]Required

Images / GIFs / video attached to the message

Child attributes
kindstringRequired
  • "image"
  • "gif"
  • "video"
urlstringRequired

Displayable URL (image, GIF, or video poster)

videoUrlstring | null

Playable video source (for video, and an mp4 alt for a GIF)

altTextstring | null
widthnumber | null
heightnumber | null
permalinkUrlstring | nullRequired
createdAtstring | nullRequired

ISO 8601

platformReplyIdstring | nullRequired

Remote id of this reply — the target when replying to it

parentPlatformIdstring | nullRequired

Remote id of the post/reply this one replies to (thread structure)

contentExpiredbooleanRequired

The text, media or author has passed the platform's retention window and been dropped; the detail read re-fetches them when it can.

textExpiredbooleanRequired

Narrower than contentExpired: the text and media themselves have passed the retention window (LinkedIn: 48 hours), rather than only the author's profile (24 hours). An empty text with this false means the platform never supplied any.

400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
404Error

The resource does not exist

Response attributes
errorstringRequired
issuesany[]
POST /api/v1/conversations/{conversationId}/read
curl -X POST "https://orbitwrite.com/api/v1/conversations/{conversationId}/read" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "organizationId": "string"
}'
Response
{
  "id": "string",
  "platform": "string",
  "accountId": "string",
  "type": "reply",
  "status": "open",
  "participant": {
    "handle": "string",
    "displayName": "string",
    "avatarUrl": "string"
  },
  "lastMessagePreview": "string",
  "lastMediaKind": "image",
  "lastMessageAt": "string",
  "unread": true,
  "snoozedUntil": "string",
  "assigneeUserId": "string",
  "contentExpired": true,
  "originalPost": {
    "id": "string",
    "groupId": "string",
    "text": "string",
    "platformUrl": "string",
    "platformPostId": "string",
    "author": {
      "handle": "string",
      "avatarUrl": "string"
    },
    "createdAt": "string"
  },
  "messages": [
    {
      "id": "string",
      "direction": "in",
      "author": {
        "handle": "string",
        "displayName": "string",
        "avatarUrl": "string"
      },
      "text": "string",
      "media": [
        {
          "kind": "image",
          "url": "string",
          "videoUrl": "string",
          "altText": "string",
          "width": 0,
          "height": 0
        }
      ],
      "permalinkUrl": "string",
      "createdAt": "string",
      "platformReplyId": "string",
      "parentPlatformId": "string",
      "contentExpired": true,
      "textExpired": true
    }
  ]
}

Mark a conversation unread#

POST/api/v1/conversations/{conversationId}/unread

Requires inbox:update. Clears the shared read watermark so the conversation shows as unread again (when its latest activity is an incoming reply). The inverse of /read.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Path parameters

conversationIdstringRequired

At least 1 character.

Body application/json

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

Responses

200ConversationDetail

The updated conversation

Response attributes
idstringRequired
platformstringRequired

Platform id, e.g. "bluesky"

accountIdstringRequired
typestringRequired
  • "reply"
  • "mention"
statusstringRequired
  • "open"
  • "resolved"
  • "snoozed"
participantConversationParticipantRequired
Child attributes
handlestringRequired
displayNamestringRequired
avatarUrlstring | nullRequired
lastMessagePreviewstringRequired
lastMediaKindstring | nullRequired

Media kind of the latest reply for a list glyph; null if text-only

  • "image"
  • "gif"
  • "video"
  • null
lastMessageAtstring | nullRequired

ISO 8601

unreadbooleanRequired
snoozedUntilstring | nullRequired

ISO 8601 wake time when status is "snoozed"; null otherwise

assigneeUserIdstring | nullRequired

User id of the teammate who owns this conversation; null when unassigned

contentExpiredbooleanRequired

The participant or preview has passed the platform's retention window (LinkedIn caches member profiles for 24 hours and keeps member posts and comments for 48) and been dropped. The list and detail reads re-fetch them when they can.

originalPostobject | nullRequired

The published post being replied to, pinned on top

Child attributes
idstringRequired

The post row this conversation hangs off (the inbox's postId), or the platform's own id for a native post.

groupIdstring | nullRequired

The post's composer group — what GET /posts/draft, score and schedule take. Null for a post not published through Orbitwrite.

textstringRequired
platformUrlstring | nullRequired
platformPostIdstring | nullRequired
authorobjectRequired
Child attributes
handlestringRequired
avatarUrlstring | nullRequired
createdAtstring | nullRequired
messagesConversationMessage[]Required
Child attributes
idstringRequired
directionstringRequired
  • "in"
  • "out"
authorConversationParticipantRequired
Child attributes
handlestringRequired
displayNamestringRequired
avatarUrlstring | nullRequired
textstringRequired
mediaConversationMedia[]Required

Images / GIFs / video attached to the message

Child attributes
kindstringRequired
  • "image"
  • "gif"
  • "video"
urlstringRequired

Displayable URL (image, GIF, or video poster)

videoUrlstring | null

Playable video source (for video, and an mp4 alt for a GIF)

altTextstring | null
widthnumber | null
heightnumber | null
permalinkUrlstring | nullRequired
createdAtstring | nullRequired

ISO 8601

platformReplyIdstring | nullRequired

Remote id of this reply — the target when replying to it

parentPlatformIdstring | nullRequired

Remote id of the post/reply this one replies to (thread structure)

contentExpiredbooleanRequired

The text, media or author has passed the platform's retention window and been dropped; the detail read re-fetches them when it can.

textExpiredbooleanRequired

Narrower than contentExpired: the text and media themselves have passed the retention window (LinkedIn: 48 hours), rather than only the author's profile (24 hours). An empty text with this false means the platform never supplied any.

400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
404Error

The resource does not exist

Response attributes
errorstringRequired
issuesany[]
POST /api/v1/conversations/{conversationId}/unread
curl -X POST "https://orbitwrite.com/api/v1/conversations/{conversationId}/unread" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "organizationId": "string"
}'
Response
{
  "id": "string",
  "platform": "string",
  "accountId": "string",
  "type": "reply",
  "status": "open",
  "participant": {
    "handle": "string",
    "displayName": "string",
    "avatarUrl": "string"
  },
  "lastMessagePreview": "string",
  "lastMediaKind": "image",
  "lastMessageAt": "string",
  "unread": true,
  "snoozedUntil": "string",
  "assigneeUserId": "string",
  "contentExpired": true,
  "originalPost": {
    "id": "string",
    "groupId": "string",
    "text": "string",
    "platformUrl": "string",
    "platformPostId": "string",
    "author": {
      "handle": "string",
      "avatarUrl": "string"
    },
    "createdAt": "string"
  },
  "messages": [
    {
      "id": "string",
      "direction": "in",
      "author": {
        "handle": "string",
        "displayName": "string",
        "avatarUrl": "string"
      },
      "text": "string",
      "media": [
        {
          "kind": "image",
          "url": "string",
          "videoUrl": "string",
          "altText": "string",
          "width": 0,
          "height": 0
        }
      ],
      "permalinkUrl": "string",
      "createdAt": "string",
      "platformReplyId": "string",
      "parentPlatformId": "string",
      "contentExpired": true,
      "textExpired": true
    }
  ]
}

Snooze a conversation until a time#

POST/api/v1/conversations/{conversationId}/snooze

Requires inbox:update. Hides the conversation from the open list until until, moving it to the shared "snoozed" category. A background sweep returns it to the open list (as unread) when that time passes.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Path parameters

conversationIdstringRequired

At least 1 character.

Body application/json

organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

untilstringRequired

ISO 8601 wake time; must be in the future

Format date-time.

Responses

200ConversationDetail

The snoozed conversation

Response attributes
idstringRequired
platformstringRequired

Platform id, e.g. "bluesky"

accountIdstringRequired
typestringRequired
  • "reply"
  • "mention"
statusstringRequired
  • "open"
  • "resolved"
  • "snoozed"
participantConversationParticipantRequired
Child attributes
handlestringRequired
displayNamestringRequired
avatarUrlstring | nullRequired
lastMessagePreviewstringRequired
lastMediaKindstring | nullRequired

Media kind of the latest reply for a list glyph; null if text-only

  • "image"
  • "gif"
  • "video"
  • null
lastMessageAtstring | nullRequired

ISO 8601

unreadbooleanRequired
snoozedUntilstring | nullRequired

ISO 8601 wake time when status is "snoozed"; null otherwise

assigneeUserIdstring | nullRequired

User id of the teammate who owns this conversation; null when unassigned

contentExpiredbooleanRequired

The participant or preview has passed the platform's retention window (LinkedIn caches member profiles for 24 hours and keeps member posts and comments for 48) and been dropped. The list and detail reads re-fetch them when they can.

originalPostobject | nullRequired

The published post being replied to, pinned on top

Child attributes
idstringRequired

The post row this conversation hangs off (the inbox's postId), or the platform's own id for a native post.

groupIdstring | nullRequired

The post's composer group — what GET /posts/draft, score and schedule take. Null for a post not published through Orbitwrite.

textstringRequired
platformUrlstring | nullRequired
platformPostIdstring | nullRequired
authorobjectRequired
Child attributes
handlestringRequired
avatarUrlstring | nullRequired
createdAtstring | nullRequired
messagesConversationMessage[]Required
Child attributes
idstringRequired
directionstringRequired
  • "in"
  • "out"
authorConversationParticipantRequired
Child attributes
handlestringRequired
displayNamestringRequired
avatarUrlstring | nullRequired
textstringRequired
mediaConversationMedia[]Required

Images / GIFs / video attached to the message

Child attributes
kindstringRequired
  • "image"
  • "gif"
  • "video"
urlstringRequired

Displayable URL (image, GIF, or video poster)

videoUrlstring | null

Playable video source (for video, and an mp4 alt for a GIF)

altTextstring | null
widthnumber | null
heightnumber | null
permalinkUrlstring | nullRequired
createdAtstring | nullRequired

ISO 8601

platformReplyIdstring | nullRequired

Remote id of this reply — the target when replying to it

parentPlatformIdstring | nullRequired

Remote id of the post/reply this one replies to (thread structure)

contentExpiredbooleanRequired

The text, media or author has passed the platform's retention window and been dropped; the detail read re-fetches them when it can.

textExpiredbooleanRequired

Narrower than contentExpired: the text and media themselves have passed the retention window (LinkedIn: 48 hours), rather than only the author's profile (24 hours). An empty text with this false means the platform never supplied any.

400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
404Error

The resource does not exist

Response attributes
errorstringRequired
issuesany[]
POST /api/v1/conversations/{conversationId}/snooze
curl -X POST "https://orbitwrite.com/api/v1/conversations/{conversationId}/snooze" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "until": "2026-10-01T09:00:00Z"
}'
Response
{
  "id": "string",
  "platform": "string",
  "accountId": "string",
  "type": "reply",
  "status": "open",
  "participant": {
    "handle": "string",
    "displayName": "string",
    "avatarUrl": "string"
  },
  "lastMessagePreview": "string",
  "lastMediaKind": "image",
  "lastMessageAt": "string",
  "unread": true,
  "snoozedUntil": "string",
  "assigneeUserId": "string",
  "contentExpired": true,
  "originalPost": {
    "id": "string",
    "groupId": "string",
    "text": "string",
    "platformUrl": "string",
    "platformPostId": "string",
    "author": {
      "handle": "string",
      "avatarUrl": "string"
    },
    "createdAt": "string"
  },
  "messages": [
    {
      "id": "string",
      "direction": "in",
      "author": {
        "handle": "string",
        "displayName": "string",
        "avatarUrl": "string"
      },
      "text": "string",
      "media": [
        {
          "kind": "image",
          "url": "string",
          "videoUrl": "string",
          "altText": "string",
          "width": 0,
          "height": 0
        }
      ],
      "permalinkUrl": "string",
      "createdAt": "string",
      "platformReplyId": "string",
      "parentPlatformId": "string",
      "contentExpired": true,
      "textExpired": true
    }
  ]
}

Reply in a conversation#

POST/api/v1/conversations/{conversationId}/messages

Publishes a reply through the platform (reusing the adapter's comment path — no scheduled post is created) and appends it to the thread, when the caller holds inbox:reply. A caller who lacks it but holds approval:request (a gated member, or a key scoped that way) does not 403: the reply is captured as a blocking approval and returned with 202 — it never reaches the platform until an approval:decide holder releases it (see /conversations/pending-replies). The reply targets the conversation's post, or the specific comment named by replyToMessageId.

Authentication

An API key or OAuth access token as a bearer token, or a signed-in session.

Path parameters

conversationIdstringRequired

At least 1 character.

Body application/json

textstring

Defaults to "".

replyToMessageIdstring | null

Reply to a specific comment (its message id). Omit to reply to the post.

mediaobject[]

Optional attachments (e.g. a GIF)

Child attributes
urlstringRequired
mimeTypestringRequired
altTextstring
sourceUrlstring
videoUrlstring
widthnumber
heightnumber
bytesnumber
organizationIdstring

Session callers only — an API key already determines the workspace.

At least 1 character.

Responses

200ConversationDetail

The conversation with the sent reply appended

Response attributes
idstringRequired
platformstringRequired

Platform id, e.g. "bluesky"

accountIdstringRequired
typestringRequired
  • "reply"
  • "mention"
statusstringRequired
  • "open"
  • "resolved"
  • "snoozed"
participantConversationParticipantRequired
Child attributes
handlestringRequired
displayNamestringRequired
avatarUrlstring | nullRequired
lastMessagePreviewstringRequired
lastMediaKindstring | nullRequired

Media kind of the latest reply for a list glyph; null if text-only

  • "image"
  • "gif"
  • "video"
  • null
lastMessageAtstring | nullRequired

ISO 8601

unreadbooleanRequired
snoozedUntilstring | nullRequired

ISO 8601 wake time when status is "snoozed"; null otherwise

assigneeUserIdstring | nullRequired

User id of the teammate who owns this conversation; null when unassigned

contentExpiredbooleanRequired

The participant or preview has passed the platform's retention window (LinkedIn caches member profiles for 24 hours and keeps member posts and comments for 48) and been dropped. The list and detail reads re-fetch them when they can.

originalPostobject | nullRequired

The published post being replied to, pinned on top

Child attributes
idstringRequired

The post row this conversation hangs off (the inbox's postId), or the platform's own id for a native post.

groupIdstring | nullRequired

The post's composer group — what GET /posts/draft, score and schedule take. Null for a post not published through Orbitwrite.

textstringRequired
platformUrlstring | nullRequired
platformPostIdstring | nullRequired
authorobjectRequired
Child attributes
handlestringRequired
avatarUrlstring | nullRequired
createdAtstring | nullRequired
messagesConversationMessage[]Required
Child attributes
idstringRequired
directionstringRequired
  • "in"
  • "out"
authorConversationParticipantRequired
Child attributes
handlestringRequired
displayNamestringRequired
avatarUrlstring | nullRequired
textstringRequired
mediaConversationMedia[]Required

Images / GIFs / video attached to the message

Child attributes
kindstringRequired
  • "image"
  • "gif"
  • "video"
urlstringRequired

Displayable URL (image, GIF, or video poster)

videoUrlstring | null

Playable video source (for video, and an mp4 alt for a GIF)

altTextstring | null
widthnumber | null
heightnumber | null
permalinkUrlstring | nullRequired
createdAtstring | nullRequired

ISO 8601

platformReplyIdstring | nullRequired

Remote id of this reply — the target when replying to it

parentPlatformIdstring | nullRequired

Remote id of the post/reply this one replies to (thread structure)

contentExpiredbooleanRequired

The text, media or author has passed the platform's retention window and been dropped; the detail read re-fetches them when it can.

textExpiredbooleanRequired

Narrower than contentExpired: the text and media themselves have passed the retention window (LinkedIn: 48 hours), rather than only the author's profile (24 hours). An empty text with this false means the platform never supplied any.

202object

The caller can't publish directly; the reply is held for approval

Response attributes
heldbooleanRequired
pendingReplyPendingReplySummaryRequired
Child attributes
idstringRequired
conversationIdstringRequired
organizationIdstringRequired
statusstringRequired
  • "pending"
  • "approved"
  • "rejected"
  • "sent"
  • "failed"
bodystringRequired
mediaPendingReplyMedia[]Required
Child attributes
urlstringRequired
mimeTypestringRequired
altTextstring
sourceUrlstring
videoUrlstring
widthnumber
heightnumber
bytesnumber
replyToMessageIdstring | nullRequired
decisionNotestring | nullRequired
sendErrorstring | nullRequired

Why the platform send failed, for a failed reply

createdAtstringRequired

ISO 8601

decidedAtstring | nullRequired

ISO 8601

decidablebooleanRequired

Whether an approval:decide holder can act on it now: pending, failed, or approved with a send that never finished (retryable after 10 minutes)

draftedByPendingReplyUserRequired
Child attributes
idstringRequired
namestringRequired
avatarUrlstring | nullRequired
decidedByPendingReplyUser | any | nullRequired
Child attributes
idstringRequired
namestringRequired
avatarUrlstring | nullRequired
conversationobjectRequired
Child attributes
platformstringRequired
participantHandlestringRequired
400Error

Invalid request

Response attributes
errorstringRequired
issuesany[]
401Error

Not signed in

Response attributes
errorstringRequired
issuesany[]
403Error

Not a member of the organization

Response attributes
errorstringRequired
issuesany[]
404Error

The resource does not exist

Response attributes
errorstringRequired
issuesany[]
429Error

Rate limit exceeded

Response attributes
errorstringRequired
issuesany[]
502object

The platform rejected the reply

Response attributes
errorstringRequired
POST /api/v1/conversations/{conversationId}/messages
curl -X POST "https://orbitwrite.com/api/v1/conversations/{conversationId}/messages" \
  -H "Authorization: Bearer $ORBITWRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "text": "",
  "replyToMessageId": "string",
  "media": [
    {
      "url": "string",
      "mimeType": "string"
    }
  ],
  "organizationId": "string"
}'
Response
{
  "id": "string",
  "platform": "string",
  "accountId": "string",
  "type": "reply",
  "status": "open",
  "participant": {
    "handle": "string",
    "displayName": "string",
    "avatarUrl": "string"
  },
  "lastMessagePreview": "string",
  "lastMediaKind": "image",
  "lastMessageAt": "string",
  "unread": true,
  "snoozedUntil": "string",
  "assigneeUserId": "string",
  "contentExpired": true,
  "originalPost": {
    "id": "string",
    "groupId": "string",
    "text": "string",
    "platformUrl": "string",
    "platformPostId": "string",
    "author": {
      "handle": "string",
      "avatarUrl": "string"
    },
    "createdAt": "string"
  },
  "messages": [
    {
      "id": "string",
      "direction": "in",
      "author": {
        "handle": "string",
        "displayName": "string",
        "avatarUrl": "string"
      },
      "text": "string",
      "media": [
        {
          "kind": "image",
          "url": "string",
          "videoUrl": "string",
          "altText": "string",
          "width": 0,
          "height": 0
        }
      ],
      "permalinkUrl": "string",
      "createdAt": "string",
      "platformReplyId": "string",
      "parentPlatformId": "string",
      "contentExpired": true,
      "textExpired": true
    }
  ]
}