Help
Help
Messages
Post, list, reply to, react to, and cross-post messages. The feed combines public messages, your own messages, and messages from people you follow.
Endpoint table
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/messages | Public (optional auth) | List messages. Unauthenticated returns public messages; a logged-in session/token personalises the feed. Query: limit, offset, onlyMine (bool), tag (string). |
| GET | /api/messages/search | Session or Bearer | Search top-level messages by content (case-insensitive substring), scoped to your feed visibility. Query: q (required, 1–200 chars), limit (default 20, max 100), offset (default 0), onlyMine (bool, default false). |
| POST | /api/messages | Session or Bearer | Create a message (see body reference below). Free for a plain text post; a subscription is required only when the post includes cross-posting, image/video, or scheduling. Returns 201. |
| GET | /api/messages/:id | Public (optional auth) | Get one message by ID. A public message is viewable without auth. |
| PATCH | /api/messages/:id | Session or Bearer | Update a future-scheduled message (scheduledAt, scheduledCrossPostConfig). |
| DELETE | /api/messages/:id | Session or Bearer | Delete a message (own messages only). Cascades replies and blob media. Returns 409 if other posts still push this message (remove those pushes first). |
| GET | /api/messages/scheduled | Session or Bearer | Upcoming scheduled messages. Query: range (today, week, or month, default month). |
| GET | /api/messages/:id/replies | Public (optional auth) | Replies to a message. Returns 200 with no auth for a publicly-visible message; a private message's replies require the owner's session cookie. |
| POST | /api/messages/:id/dig | Session or Bearer | Add an I Dig! reaction (idempotent). Returns { digCount, dugByMe, isNewDig } (isNewDig is false when you had already dug it). |
| DELETE | /api/messages/:id/dig | Session or Bearer | Remove your dig. |
| POST | /api/messages/:id/report | Session or Bearer | Report a message. Body: { reason, detail? }. |
| POST | /api/messages/images/upload | Session or Bearer | Upload an image for attachment. Subscriber only. |
| POST | /api/messages/videos/upload | Session or Bearer | Upload a video for attachment. Subscriber only. |
Listing messages
GET /api/messages?onlyMine=true&limit=2&offset=0
Authorization: Bearer 3f1c9e...<64 hex chars>...a8
{
"messages": [
{
"id": "msg_001",
"content": "Just shipped a new feature!",
"publiclyVisible": true,
"tags": ["dev", "release"],
"digCount": 4,
"dugByMe": false,
"replyCount": 1,
"createdAt": "2025-06-10T14:22:00.000Z",
"user": { "id": "...", "username": "yourhandle", "displayName": "Your Name", "avatar": null }
}
],
"pagination": { "total": 42, "limit": 2, "offset": 0, "hasMore": true }
}
The list is returned under the top-level messages key (not data), and each message's author is under user (with an avatar field): there is no author/avatarUrl.
Searching messages
GET /api/messages/search?q=feature&limit=20&onlyMine=false
Authorization: Bearer 3f1c9e...<64 hex chars>...a8
Matching is a case-insensitive substring over message content, restricted to top-level messages (replies excluded) and scoped to your feed visibility (honors your viewingPreference). Each item uses the same message shape as GET /api/messages. The response wraps results in { "messages": [ ... ], "pagination": { "total", "limit", "offset", "hasMore" } }. An empty or over-200-character q, or a limit above 100, returns 400.
Creating a message
Body fields
| Field | Type | Description |
|---|---|---|
content | string | Required unless pushing with no comment. Max length from your account setting (default 666 chars). |
publiclyVisible | boolean | Defaults to your account's default visibility. |
parentId | string | Reply to this message ID. Mutually exclusive with pushedMessageId. |
pushedMessageId | string | Repost this public message ID. content may be empty (plain repost) or non-empty (repost with comment). |
tags | string[] | Free-form string labels. Case-sensitive; lowercase recommended. To discover or autocomplete existing public tags, see the tag-discovery endpoints in Utility Endpoints. |
imageUrls | string[] | Up to 8 URLs from POST /api/messages/images/upload. Subscriber only. |
videoUrls | string[] | 1 URL from POST /api/messages/videos/upload. Subscriber only. |
scheduledAt | string (ISO 8601) | Future datetime to publish. Cannot combine with parentId or pushedMessageId. Subscriber only. |
mastodonProviderIds | string[] | Linked Mastodon identity IDs (from GET /api/user/identities) to cross-post to. Subscriber only. |
crossPostToBluesky | boolean | Cross-post to linked Bluesky account. Subscriber only. |
crossPostToLinkedIn | boolean | Cross-post to linked LinkedIn account. Subscriber only. |
crossPostToTwitter | boolean | Cross-post to linked X (Twitter) account. Subscriber only. |
Simple public message
POST /api/messages
Authorization: Bearer 3f1c9e...<64 hex chars>...a8
Content-Type: application/json
{ "content": "Hello from the API!", "publiclyVisible": true, "tags": ["api"] }
Reply
POST /api/messages
Content-Type: application/json
{ "content": "Great point.", "publiclyVisible": true, "parentId": "msg_001" }
Scheduled cross-post (subscriber)
POST /api/messages
Content-Type: application/json
{
"content": "Launching at 9 AM tomorrow!",
"publiclyVisible": true,
"scheduledAt": "2025-09-01T13:00:00.000Z",
"crossPostToBluesky": true,
"crossPostToTwitter": true,
"mastodonProviderIds": ["clx9abc000002"]
}
Creation response
The 201 response has this shape:
{
"message": "Message created successfully",
"data": { "id": "msg_003", "content": "...", "publiclyVisible": true, "createdAt": "..." },
"scheduledAt": "2025-09-01T13:00:00.000Z",
"crossPostResults": [ ... ],
"crossPosts": [ ... ],
"org": { ... }
}
-
data: the created message object. -
scheduledAt: present only for scheduled posts (echoed back). -
org: present only when the post targets an organization. -
crossPosts: always present (may be empty). Each entry:{ "platform": "mastodon", "providerId": "clx9abc000002", "status": "ok", "externalUrl": "https://mastodon.social/@you/123", "error": null }platformis one of"mastodon" | "bluesky" | "linkedin" | "twitter"and is always present here.providerId,externalUrl, anderrorare optional;statusis"ok" | "failed" | "pending". -
crossPostResults: present only when non-empty. Each entry:{ "providerId": "clx9abc000002", "instanceName": "mastodon.social", "success": true, "url": "https://mastodon.social/@you/123", "error": null, "errorCode": null, "statusCode": 200 }This array has no
platformfield.url,error,errorCode, andstatusCodeare optional.
Guidance: read the platform from crossPosts[].platform, not from crossPostResults[].
Uploading images and videos
Two-step flow: upload first, then reference the URL in imageUrls / videoUrls.
POST /api/messages/images/upload
Content-Type: multipart/form-data
file=<binary>
Response: { "url": "https://cdn.interlinedlist.com/images/abc123.webp" }
Image constraints: JPEG/PNG/WebP/GIF; auto-resized to 1200 px max side; ≤ 1.4 MB output.
Video constraints: MP4/WebM/QuickTime/AVI; max 3 MB; no server transcoding.
Cross-posting details
Cross-posting only works when the corresponding provider identity is linked to your account. See Authentication & OAuth for linking flows. For Mastodon, use the id of the identity from GET /api/user/identities (not the handle). LinkedIn additionally supports posting to organization pages: see LinkedIn Integration and Organizations.
Reactions and replies
POST /api/messages/msg_001/dig # → { "digCount": 5, "dugByMe": true, "isNewDig": true }
DELETE /api/messages/msg_001/dig # → { "digCount": 4, "dugByMe": false }
GET /api/messages/msg_001/replies # → array of reply messages
Related
- Messages (Help Center): the user-facing guide to posting, replies, scheduling, and cross-posting.
- LinkedIn Integration: personal and organization LinkedIn posting targets.
- Authentication & OAuth: linking the provider identities that cross-posting requires.
- API overview: base URL, authentication at a glance, and response conventions.
- API explorer: try message endpoints live with the interactive Swagger console.