Skip to main content
Members can save content nodes to a personal list (“My List”) within a hub. Saves persist across sessions, survive subscription lapses, and are always consistent with what the member can actually open right now.
All three routes also resolve under the /api prefix (no v1).

Saving an item

Send the content node’s ID in the request body:
Returns 201 with the saved_items resource:
Idempotent. Saving the same node a second time returns 201 with the original row — the created_at date and list position are not changed. No duplicate event is emitted. This makes double-taps from the UI safe to retry. Access-gated. You can only save a node you can currently open. If the node is missing or the member does not have access, the API returns 404 — the same response for both cases, so no information about whether the node exists leaks.

Unsaving an item

Returns 204 always. Unsaving a node that was never saved is not an error. The path parameter is the content_node_id, not the saved_items row ID.

Retrieving the list

Returns saved items newest-first, with full content_nodes resources in the top-level included array so the frontend can render cards without additional fetches:
Pagination uses page[size] (1–100, default 20) and page[after] (cursor from the previous response’s links.next). See pagination for details.

Access behavior

Items whose access has been revoked are hidden from the list — they do not appear but are not deleted. If the member’s access is restored, the item reappears with its original save date. This means saving a node during a subscription and then losing access does not silently discard the bookmark; it comes back exactly where it was when the subscription renews. Consequently, the list length may be shorter than page[size] even when has_more is true — the cursor still advances correctly past hidden items.

is_saved on content reads

The portal content routes include an is_saved boolean on every content_nodes resource so the UI can show the bookmark state inline without a separate request:
is_saved is false for unauthenticated requests.

Auth and rate limits

All three endpoints require a contact JWT (hub member). Anonymous requests return 401. A non-member returns 403.

v1 scope

Saved items currently target content nodes only. The underlying data model supports other target types (discussions, members) — those will be exposed in a future release without a contract change.