{
  "info": {
    "name": "Commune: Build an app every creator can connect",
    "description": "An API key works for your own newsletter. To build something other creators use, they need a way to say yes without copying a secret into your app. Commune lets them connect your app from a consent screen, pick the newsletters it may reach and see exactly what it may do, and take it back whenever they like.\n\nThe walkthrough: https://usecommune.dev/use-cases/build-an-integration\n\nSet the `accessToken` variable to an access token from the authorization code flow the walkthrough describes, 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": "{{accessToken}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://api.usecommune.com"
    },
    {
      "key": "accessToken",
      "value": ""
    },
    {
      "key": "version",
      "value": "2026-08-26"
    },
    {
      "key": "newsletter",
      "value": "example-letter"
    }
  ],
  "item": [
    {
      "name": "1. See who connected",
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Commune-Version",
            "value": "{{version}}"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/me",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "me"
          ]
        },
        "description": "From here on your app talks to the API, and **the bearer on every request is the access token**, sent exactly as an API key would be. Send `Commune-Version` as well: without it the connection is pinned to whichever version was current when the creator consented, a version your code never chose.\n\nThis request takes any credential and needs no scope, so it works whatever the creator granted. Use `id` as the key for this creator in your own database. `display_name` can be empty, so fall back to `username`."
      }
    },
    {
      "name": "2. Find the newsletters they ticked",
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Commune-Version",
            "value": "{{version}}"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/newsletters",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "newsletters"
          ]
        },
        "description": "One connection covers every newsletter the creator ticked, and this is where you learn which. It returns those newsletters and nothing else, so read it rather than assuming there is one. Keep each `handle` or `id` (either works in a path): every other request names one.\n\nCall it again whenever it matters. What the token reaches is recomputed on every request from what the creator granted and what they can still do: if they leave a newsletter's team, or an owner cuts your app off one newsletter, it drops out of this list with nothing else changing."
      }
    },
    {
      "name": "3. Read what they granted you",
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Commune-Version",
            "value": "{{version}}"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/newsletters/{{newsletter}}/articles",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "newsletters",
            "{{newsletter}}",
            "articles"
          ]
        },
        "description": "Now the work your app exists for. This needs `content:read`, which is what it asked for, and returns the newsletter's published articles, newest first, 20 at a time; follow `pagination.next_cursor` for more.\n\nA request that needs more than the creator granted answers `403` with `insufficient_scope`, and `allowed_values` names the scope that would have worked. The fix is not a retry: it is another trip through the consent screen asking for the full set you now need."
      }
    }
  ]
}
