Export comments for reporting, archival, and reconciliation
Read thread snapshots, retrieve one conversation, or drain the fund-wide comment feed.
Before you start: complete the authentication and TypeScript client setup in Commenting before running these examples.
Export workflows
Use the Comment API to read conversations out of Anduin — for a full archive, a reconciliation pass after an import, or a periodic sync into your external system. Three read endpoints cover it, from coarsest to finest:
- ListCommentThreads —
GET /{fundId}/comment-threadslists every non-empty thread in the fund with itsanchor,visibility,status,assignee, and comment count. Use it for the per-conversation view — for example, to group an export by form question or to report on open versus resolved threads. - ExportFundComments —
GET /{fundId}/commentsreturns one flat feed of every comment (opening comments and replies) across the whole fund. This is the simplest way to export everything: each comment carries itsthreadId, so you can rebuild conversations on your side or join them against the thread list from step 1. - ListThreadComments —
GET /{fundId}/comment-threads/{threadId}/commentsreturns one thread's comments when you already know which conversation you want — for example, to verify an import.
What a thread snapshot looks like
This is a real ListCommentThreads response for a small demo fund — one investor order carrying its two general threads, an AML/KYC document thread, and a form-question thread:
{
"threads": [
{
"threadId": "txnoo7ed9y1mzrwy.offis00.isuyd6r57",
"anchorResourceId": "txnoo7ed9y1mzrwy.fsb4x2o.lpp9lq1n0o",
"anchorResourceType": "Order",
"anchor": { "subType": "general" },
"visibility": "internal",
"status": "open",
"createdAt": "2026-07-22T04:52:52.174Z",
"lastCommentAt": "2026-07-23T08:06:25.290Z"
},
{
"threadId": "txnoo7ed9y1mzrwy.offis00.isumg3083",
"anchorResourceId": "txnoo7ed9y1mzrwy.fsb4x2o.lpp9lq1n0o",
"anchorResourceType": "Order",
"anchor": { "subType": "general" },
"visibility": "shared",
"status": "open",
"createdAt": "2026-07-22T04:52:53.448Z",
"lastCommentAt": "2026-07-23T08:07:32.037Z"
},
{
"threadId": "txnoo7ed9y1mzrwy.offis00.isu60rgng",
"anchorResourceId": "txnoo7ed9y1mzrwy.fsb4x2o.lpp9lq1n0o",
"anchorResourceType": "Order",
"anchor": { "subType": "amlKycDocument", "docType": "W-9" },
"visibility": "internal",
"status": "open",
"createdAt": "2026-07-23T08:05:26.817Z",
"lastCommentAt": "2026-07-23T08:13:15.188Z"
},
{
"threadId": "txnoo7ed9y1mzrwy.offis00.isuvz3vl2",
"anchorResourceId": "txnoo7ed9y1mzrwy.fsb4x2o.lpp9lq1n0o",
"anchorResourceType": "Order",
"anchor": {
"subType": "formQuestion",
"formVersionId": "forocr00000000000002.fveversio0.lfv81kl0gn",
"fieldAlias": "entityname",
"tableOfContentTitle": "Section I - General Information",
"description": "1. Registration Name(s) in Which Investment Should Be Held (“Subscriber”)"
},
"visibility": "shared",
"status": "open",
"createdAt": "2026-07-23T08:12:23.236Z",
"lastCommentAt": "2026-07-23T08:13:12.612Z"
}
],
"hasMore": false
}Notice: the thread snapshot is metadata only — it never contains comment bodies. A snapshot row tells you what a conversation is about (anchor), who can see it (visibility), and where it stands (status, commentCount, lastCommentAt) — but not what was said. To read the messages, follow up with ExportFundComments (fund-wide) or ListThreadComments (one thread).
Draining the comment feed
All three read endpoints are cursor-paginated. To export every comment, page through the fund-wide feed with the standard cursor loop:
const fundId = "YOUR_FUND_ID";
const comments = [];
let cursor: string | undefined;
do {
const { data: page, error } = await client.GET("/api/v1/fundsub/{fund-id}/comments", {
params: {
path: { "fund-id": fundId },
query: { limit: 200, ...(cursor ? { cursor } : {}) },
},
});
if (error) throw new Error(JSON.stringify(error));
comments.push(...page.comments);
cursor = page.hasMore ? page.nextCursor : undefined;
} while (cursor);Each element of the feed is one comment. Here are two consecutive comments from the same fund's feed (abridged) — note how you tell an imported comment apart from one typed in the application:
[
{
"commentId": "txnoo7ed9y1mzrwy.offis00.isuvz3vl2.dcmroot000000",
"threadId": "txnoo7ed9y1mzrwy.offis00.isuvz3vl2",
"author": { "email": "[email protected]", "displayName": "Virginia Lee" },
"body": "<p>Should this be under my personal name or our family trust? The trust registration is still pending.</p>",
"createdAt": "2026-07-23T08:12:23.236Z",
"mentions": [],
"isRoot": true
},
{
"commentId": "txnoo7ed9y1mzrwy.offis00.isuvz3vl2.dcmjyjyqrz4oz",
"threadId": "txnoo7ed9y1mzrwy.offis00.isuvz3vl2",
"author": { "email": "[email protected]", "displayName": "Dev Service Account" },
"body": "Hi Virginia — please use the family trust, exactly as it is registered with us: \"Lee Family Trust\". We'll sync the final registration name back to the CRM once the trust paperwork completes.",
"createdAt": "2026-07-23T08:13:12.612Z",
"mentions": [],
"importedMetadata": {
"onBehalfOf": "Jordan Lee (External CRM)",
"externalRef": "crm-comment-2049"
},
"isRoot": false
}
]When reading exported comments, keep the following in mind:
importedMetadata(containing youronBehalfOfandexternalRef) identifies comments that were imported through this API. Comments typed in the Anduin application do not have it — the first comment above was typed by the investor, the second was imported.- Comments typed in the application may carry lightweight HTML in
body(the<p>wrapper above). Normalize it if your system expects plain text. - Mentions appear in
bodyas plain-text tokens:@[[email protected]]and@[team:TEAM-ID]. - The fund-wide feed is delivered at-least-once. Deduplicate the feed using
commentId.
Limits and pagination
- List endpoints return 50 records by default and support a maximum
limitof 200. - Follow
nextCursoruntilhasMoreisfalse. - Keep the same
anchorResourceIdfilter when following a cursor from a filtered request. - Treat cursors, thread IDs, and comment IDs as opaque values.
Troubleshooting
No threads are returned
The fund may have no comments yet, or its general threads may still be empty. ListCommentThreads returns only non-empty threads.
The API returns 403
Confirm that the API service account can read the thread's visibility tier. Internal comments require fund-team access.
The API returns 404 for a thread
Confirm that the threadId belongs to the fund in the request URL. Thread IDs cannot be used across funds.
Endpoints used
All paths below are relative to /api/v1/fundsub.
| Operation | Method and path | Purpose |
|---|---|---|
| ListCommentThreads | GET /{fundId}/comment-threads | List non-empty comment threads in a fund. |
| ListThreadComments | GET /{fundId}/comment-threads/{threadId}/comments | Read comments in one thread. |
| ExportFundComments | GET /{fundId}/comments | Export the fund-wide comment feed. |
Updated 14 days ago