Shop It Docs
Developer ResourcesCommunication

Communication Mobile API Reference

Integration reference for Communication mobile channel read endpoints.

Communication Mobile API Reference

Audience: Mobile/frontend developers
Scope: Mobile channel + discussion contracts currently implemented.


Mobile APIs

Realtime Integration

Mobile clients can join communication websocket rooms for live channel-post and discussion-message deltas. For room names, join/sync socket events, replay flow, and payload contracts, see Communication Realtime Implementation.

Access vs Join

Communication mobile now distinguishes:

  • Access policy: decides whether the user can read the channel right now.
  • Join state: decides whether the user is subscribed to broadcast post notifications.

Rules:

  • OPEN channels remain readable even if the user never joins.
  • EXTERNAL_GATED channels require current entitlement to read.
  • Joining does not grant read access by itself.
  • Leaving stops future broadcast notifications, but does not remove content access for OPEN or currently-entitled gated channels.
  • If a joined gated user loses entitlement, the channel becomes joined but locked and opens into a resubscribe/paywall flow. Posts and discussion stay blocked.

List Channels

Endpoint

GET /api/mobile/channels?cursor=&limit=

Auth

  • Optional JWT (OptionalJwtAuthGuard)
  • Public/open channels can be listed without login.
  • Gated/private visibility is still evaluated by access policy.

Query params

ParamTypeRequiredExampleNotes
cursorstringNoeyJjcmVhdGVkQXQiOiI...Opaque cursor token
limitnumberNo20Default 20, max 100

Response item fields

  • id, kind, accessPolicy, status, visibility, title, description, createdAt, updatedAt
  • isJoined: whether the authenticated user has joined the channel for notifications
  • isLocked: whether the channel is joined but currently blocked by gated access loss

Common error scenarios

  • 422: invalid cursor value.

Get Channel Detail

Endpoint

GET /api/mobile/channels/{id}

Auth

  • Optional JWT (OptionalJwtAuthGuard)
  • Access policy enforcement still applies for gated channels.

Path params

ParamTypeRequiredExampleNotes
idnumberYes3Channel ID

Response

  • Returns channel metadata: id, kind, accessPolicy, status, visibility, title, description, createdAt, updatedAt, isJoined, isLocked

Locked-channel behavior:

  • If a joined gated user loses entitlement, detail may still return the channel shell with isJoined = true and isLocked = true.
  • Frontend should open a resubscribe/paywall screen instead of trying to render posts.

Common error scenarios

  • 400: invalid non-numeric id.
  • 403: user is not entitled to read the channel.
  • 404: channel not found.

Join Channel

Endpoint

POST /api/mobile/channels/{id}/join

Auth

  • Authorization: Bearer <user-jwt>

Behavior

  • Supported for broadcast channels only.
  • Current channel access must pass before join succeeds.
  • Idempotent: joining an already-joined channel returns the active joined state again.

Response

{
	"message": "Channel joined successfully",
	"data": {
		"channelId": 3,
		"isJoined": true,
		"joinedAt": "2026-03-19T12:00:00.000Z",
		"leftAt": null
	}
}

Leave Channel

Endpoint

POST /api/mobile/channels/{id}/leave

Auth

  • Authorization: Bearer <user-jwt>

Behavior

  • Supported for broadcast channels only.
  • Idempotent.
  • Works even if the user already lost gated access.
  • Leaving stops future broadcast push notifications immediately.

Response

{
	"message": "Channel left successfully",
	"data": {
		"channelId": 3,
		"isJoined": false,
		"joinedAt": "2026-03-10T10:00:00.000Z",
		"leftAt": "2026-03-19T12:30:00.000Z"
	}
}

List Channel Posts (Cursor Pagination)

Endpoint

GET /api/mobile/channels/{id}/posts?after_id=&before_id=&limit=

Auth

  • Optional JWT (OptionalJwtAuthGuard)
  • Access policy still applies (OPEN channels can be read publicly, EXTERNAL_GATED channels require entitlement decision).

Path params

ParamTypeRequiredExampleNotes
idnumberYes3Channel ID

Query params

ParamTypeRequiredExampleNotes
after_idstringNo2Return newer posts where id > after_id
before_idstringNo4Return older posts where id < before_id
limitnumberNo20Default 20, max 100

Important rules

  • Send only one of after_id or before_id in the same request.
  • id is the canonical channel post cursor and is serialized as string.
  • Channel posts are ordered by posts.id (insert order), not by publishedAt.
  • publishedAt remains metadata for display and access-window checks.
  • Cursor behavior:
    • next_after_id: newest post id in current page.
    • next_before_id: oldest post id in current page.

How ordering works

  • after_id mode (catch-up/newer): ascending order by post id.
  • before_id mode (scroll older): descending order by post id.

Real test example (channel 3 has post ids 1, 2, 3)

Case A: Initial newer window

GET /api/mobile/channels/3/posts?after_id=0&limit=2

Expected shape:

  • items: post ids 1, 2
  • cursor.next_after_id: "2"
  • cursor.next_before_id: "1"
  • has_more: true (because post id 3 still exists)

Case B: Older page from upper boundary

GET /api/mobile/channels/3/posts?before_id=4&limit=2

Expected shape:

  • items: post ids 3, 2
  • cursor.next_after_id: "3"
  • cursor.next_before_id: "2"
  • has_more: true (because post id 1 still exists)

This is why your result is correct:

  • before_id=4 means "give me posts with id < 4".
  • Returned order is descending for older-scroll mode, so higher ids appear first.

Common error scenarios

  • 400: invalid non-numeric id.
  • 403: user is not entitled to read the channel.
  • 404: channel not found.
  • 422: invalid cursor combination/format.

Get Post Detail

Endpoint

GET /api/mobile/posts/{postId}

Auth

  • Optional JWT (OptionalJwtAuthGuard)
  • Channel and post visibility policy checks are still enforced.

Path params

ParamTypeRequiredExampleNotes
postIdnumberYes101Post ID

Response fields

  • id, channelId, publishedAt, createdByAdminId, type
  • bodyText, linkUrl, chartPayloadJson
  • isPinned, pinnedAt
  • isDeleted, deletedAt
  • attachments (structured metadata + resolved URL)
    • id, storageKey, url, fileName, mimeType, sizeBytes, displayOrder
  • createdAt, updatedAt

Common error scenarios

  • 400: invalid non-numeric postId.
  • 403: user is not entitled to read the post.
  • 404: post not found.

Get Channel Discussion

Endpoint

GET /api/mobile/channels/{id}/discussion

Auth

  • Authorization: Bearer <user-jwt>

Behavior

  • Uses the same access decision as the channel itself.
  • If the user cannot access the channel, they cannot access the discussion.
  • If the discussion has requiredFeatureKey, user must have that feature.

Important:

  • Joined notification membership does not unlock discussion access.
  • A joined gated user in grace period may still receive broadcast post push notifications, but discussion read/post/realtime access remains blocked until entitlement is restored.

Example response

{
	"message": "Channel discussion fetched successfully",
	"data": {
		"id": 1,
		"channelId": 3,
		"title": "VIP Signals Discussion",
		"isEnabled": true,
		"requiredFeatureKey": "chat.discussion",
		"slowModeEnabled": false,
		"slowModeIntervalSeconds": null,
		"createdByAdminId": "019ce156-1647-75b9-a5ba-07758a4f7675",
		"createdAt": "2026-03-16T10:00:00.000Z",
		"updatedAt": "2026-03-16T10:00:00.000Z"
	}
}

List Discussion Messages

Endpoint

GET /api/mobile/channels/{id}/discussion/messages?before_id=&limit=&view=

Auth

  • Authorization: Bearer <user-jwt>

Query params

ParamTypeRequiredNotes
before_idstringNoFetch older messages with ids lower than this value
limitnumberNoDefault 20, max 100
viewstringNofull (default) or compact

Example response (full)

{
	"message": "Channel discussion messages fetched successfully",
	"data": {
		"items": [
			{
				"id": 11,
				"discussionId": 1,
				"authorType": "ADMIN",
				"authorUserId": null,
				"authorAdminId": "019ce156-1647-75b9-a5ba-07758a4f7675",
				"body": "Wait for confirmation above resistance before entering.",
				"isDeleted": false,
				"deletedAt": null,
				"deletedByAdminId": null,
				"editedAt": null,
				"editedByUserId": null,
				"editedByAdminId": null,
				"createdAt": "2026-03-16T10:05:00.000Z",
				"updatedAt": "2026-03-16T10:05:00.000Z"
			}
		],
		"cursor": {},
		"limit": 20,
		"has_more": false,
		"count": 1
	}
}

Example response (compact)

{
	"message": "Channel discussion messages fetched successfully",
	"data": {
		"items": [
			{
				"id": 11,
				"authorType": "ADMIN",
				"authorUserId": null,
				"authorAdminId": "019ce156-1647-75b9-a5ba-07758a4f7675",
				"body": "Wait for confirmation above resistance before entering.",
				"isDeleted": false,
				"createdAt": "2026-03-16T10:05:00.000Z"
			}
		],
		"cursor": {},
		"limit": 20,
		"has_more": false,
		"count": 1
	}
}

Create Discussion Message

Endpoint

POST /api/mobile/channels/{id}/discussion/messages

Auth

  • Authorization: Bearer <user-jwt>

Raw request body

{
	"body": "I am waiting for candle confirmation before entry."
}

Behavior

  • Requires channel access.
  • Denied when the user is banned from the discussion.
  • Denied when the user is muted.
  • Slow mode is enforced for user-authored message creation.

Update Own Discussion Message

Endpoint

PATCH /api/mobile/discussion-messages/{id}

Raw request body

{
	"body": "Updated: I will wait for confirmation above resistance."
}

Delete Own Discussion Message

Endpoint

DELETE /api/mobile/discussion-messages/{id}

Update Channel Read State

Endpoint

POST /api/mobile/channels/{id}/read-state

Auth

  • JWT required (JwtAuthGuard)
  • This endpoint is not public.

Path params

ParamTypeRequiredExampleNotes
idnumberYes3Channel ID

Raw Request Body

{
	"last_seen_post_id": "1200"
}

Request field rules

  • last_seen_post_id must be a non-negative integer string.

Behavior

  • Stores per-user per-channel read cursor.
  • Uses monotonic update semantics: server keeps the max value (GREATEST(old, incoming)), so read cursor never moves backward.
  • Returns: channelId, lastSeenPostId, lastSeenAt

Common error scenarios

  • 400: invalid non-numeric id.
  • 401: missing/invalid JWT.
  • 403: user is not entitled to read the channel.
  • 404: channel not found.
  • 422: invalid last_seen_post_id format.