{
  "info": {
    "name": "Commune: Bring the conversation to your site",
    "description": "Your readers talk about each issue in Commune, and most people who find that issue on your website never see the conversation. Put it under the article on your own site, kept current as replies arrive, so every visitor sees that people are reading and answering.\n\nThe walkthrough: https://usecommune.dev/use-cases/conversation-on-your-site\n\nSet the `apiKey` variable to a key from https://usecommune.com/settings/api-keys, then run the requests in order.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{apiKey}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://api.usecommune.com"
    },
    {
      "key": "apiKey",
      "value": ""
    },
    {
      "key": "version",
      "value": "2026-08-26"
    },
    {
      "key": "newsletter",
      "value": "example-letter"
    },
    {
      "key": "thread",
      "value": "b1c2d3e4-f506-4718-8293-a4b5c6d7e8f9"
    }
  ],
  "item": [
    {
      "name": "1. Find the article and its discussion",
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Commune-Version",
            "value": "{{version}}"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/newsletters/{{newsletter}}/articles?status=sent&limit=10",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "newsletters",
            "{{newsletter}}",
            "articles"
          ],
          "query": [
            {
              "key": "status",
              "value": "sent"
            },
            {
              "key": "limit",
              "value": "10"
            }
          ]
        },
        "description": "Every request needs a key, and a key is a secret: keep it on your server and never ship it to the browser. The API answers browser requests too, so nothing stops a page from calling it directly except that anybody could then read your key from the page. The site's key should hold `content: read` and nothing else, for a reason step 2 makes clear.\n\nList the newsletter's published articles; each one names its discussion in `thread`. A read-only key only ever sees `sent` articles, and never one limited to a tag audience or dated in the future. `thread` is `null` when an article has no discussion (the imported article in the contract's example, for one). If your page already knows which article it is showing, `GET /articles/{article}` with its `short_id` returns the same `thread` for one article."
      }
    },
    {
      "name": "2. Decide which discussions are public",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Commune-Version",
            "value": "{{version}}"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{$guid}}"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/threads/{{thread}}/publish",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "threads",
            "{{thread}}",
            "publish"
          ]
        },
        "description": "A discussion starts inside your newsletter's space, with `visibility` `subscribers`: your readers wrote it for your other readers. A key holding only `read` permissions sees `public` threads and nothing else, so the site's key answers `404` for this one. That is the boundary you want on a page anybody can open, and it is why the site's key should never hold `write` in any family: a key that does sees every thread, and your page would republish words people wrote for subscribers.\n\nTo show a discussion, promote it. This request does it one thread at a time, with a separate key holding `content: write` (or do it in the Commune app). Be sure first: it also puts the thread on Commune's global feed, and no operation in the API takes it back off (the Commune app can). A thread already public answers `200` and changes nothing. It is a write, so it carries an `Idempotency-Key`."
      }
    },
    {
      "name": "3. Read the opening comment",
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Commune-Version",
            "value": "{{version}}"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/threads/{{thread}}?expand=author",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "threads",
            "{{thread}}"
          ],
          "query": [
            {
              "key": "expand",
              "value": "author"
            }
          ]
        },
        "description": "The thread is the first comment under the article, and its `content` is what Mira wrote. `expand=author` puts her public profile in place of the bare reference, so there is no second request per person. A profile is only ever `display_name`, `username` and `avatar`; no address or anything private is on it. `reply_count` is there if you want a count before you load the replies.\n\nUse the thread's `id` here. A discussion Commune opened under an article is addressed on the web through the article's own page, so do not build links from its `short_id`."
      }
    },
    {
      "name": "4. Read every reply",
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Commune-Version",
            "value": "{{version}}"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/threads/{{thread}}/messages?expand=author&limit=100",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "threads",
            "{{thread}}",
            "messages"
          ],
          "query": [
            {
              "key": "expand",
              "value": "author"
            },
            {
              "key": "limit",
              "value": "100"
            }
          ]
        },
        "description": "Replies come oldest first in one flat list. A reply to the thread has `depth` 1 and `parent` `null`; a reply to a reply has `depth` 2 and a `parent` pointing at the reply it answers, which is always in the same list, so you rebuild the tree without another request. `expand=author` works here too. Deleted replies are left out rather than marked.\n\nAsk for up to 100 at a time, and while `pagination.next_cursor` is not `null`, repeat the request with `cursor` set to it. If you ever hold only an author reference (from somewhere that does not expand), `GET /users/{user}` returns the same profile, but here expanding saves a request per person."
      }
    }
  ]
}
