{
  "info": {
    "name": "Penholder API",
    "description": "Your team's priorities, from your own tools. Create a token in your Penholder profile under API tokens, set the collection variable api_token, then run the Reading folder: it fills in team_id, project_id, topic_id, item_id, field_id, member_id and suggestion_id from your first team, project and topic. Every request checks its status. The writes change real data, so try them on a team made for it. A token acts as its person with exactly their access. Full reference: https://penholder.app/api-docs. AI assistants can connect to the MCP server at https://penholder.app/api/mcp/ with the same token.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{api_token}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://penholder.app"
    },
    {
      "key": "api_token",
      "value": "ph_YOUR_TOKEN"
    },
    {
      "key": "team_id",
      "value": "TEAM_ID"
    },
    {
      "key": "project_id",
      "value": "PROJECT_ID"
    },
    {
      "key": "topic_id",
      "value": "TOPIC_ID"
    },
    {
      "key": "item_id",
      "value": "ITEM_ID"
    },
    {
      "key": "suggestion_id",
      "value": "SUGGESTION_ID"
    },
    {
      "key": "member_id",
      "value": "MEMBER_ID"
    },
    {
      "key": "field_id",
      "value": "FIELD_ID"
    }
  ],
  "item": [
    {
      "name": "Reading",
      "description": "Anyone on a team can read it. Start with Your teams to find ids.",
      "item": [
        {
          "name": "You",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"answers 200\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/me",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "me"
              ]
            },
            "description": ""
          },
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{base_url}}/api/me",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "api",
                    "me"
                  ]
                },
                "description": ""
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"user\": {\n    \"id\": \"2c539862-0ceb-4095-836d-0ebd94711798\",\n    \"full_name\": \"Rob Mills\",\n    \"initials\": \"RM\",\n    \"avatar_url\": null,\n    \"email\": \"rob@example.com\",\n    \"pending_email\": null\n  }\n}"
            }
          ]
        },
        {
          "name": "Your teams",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"answers 200\", () => pm.response.to.have.status(200));",
                  "if (pm.response.code < 400) {",
                  "  const teams = pm.response.json().teams;",
                  "  if (teams.length) pm.collectionVariables.set(\"team_id\", teams[0].id);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/teams",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "teams"
              ]
            },
            "description": ""
          },
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{base_url}}/api/teams",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "api",
                    "teams"
                  ]
                },
                "description": ""
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"teams\": [\n    {\n      \"id\": \"62c99d17-5c7f-443c-b4ea-46df198b20b5\",\n      \"name\": \"Northwind\",\n      \"initials\": \"N\",\n      \"logo_url\": null,\n      \"role\": \"member\",\n      \"member_count\": 2,\n      \"project_count\": 1,\n      \"faces\": [\n        {\n          \"id\": \"72b37a72-42a5-4529-8cff-928a5db6757e\",\n          \"full_name\": \"Dana Kim\",\n          \"initials\": \"DK\",\n          \"avatar_url\": null\n        },\n        {\n          \"id\": \"2c539862-0ceb-4095-836d-0ebd94711798\",\n          \"full_name\": \"Rob Mills\",\n          \"initials\": \"RM\",\n          \"avatar_url\": null\n        }\n      ],\n      \"plan_status\": \"beta\",\n      \"locked\": false,\n      \"plan\": null\n    }\n  ],\n  \"billing_configured\": false\n}"
            }
          ]
        },
        {
          "name": "A team",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"answers 200\", () => pm.response.to.have.status(200));",
                  "if (pm.response.code < 400) {",
                  "  const team = pm.response.json();",
                  "  if (team.projects.length) pm.collectionVariables.set(\"project_id\", team.projects[0].id);",
                  "  pm.collectionVariables.set(\"member_id\", team.you);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/teams/{{team_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "teams",
                "{{team_id}}"
              ]
            },
            "description": ""
          },
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{base_url}}/api/teams/{{team_id}}",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "api",
                    "teams",
                    "{{team_id}}"
                  ]
                },
                "description": ""
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"team\": {\n    \"id\": \"62c99d17-5c7f-443c-b4ea-46df198b20b5\",\n    \"name\": \"Northwind\",\n    \"initials\": \"N\",\n    \"logo_url\": null,\n    \"created_at\": \"2026-09-15T17:40:30Z\"\n  },\n  \"role\": \"member\",\n  \"is_owner\": false,\n  \"you\": \"2c539862-0ceb-4095-836d-0ebd94711798\",\n  \"pen\": {\n    \"id\": \"72b37a72-42a5-4529-8cff-928a5db6757e\",\n    \"full_name\": \"Dana Kim\",\n    \"initials\": \"DK\",\n    \"avatar_url\": null\n  },\n  \"you_hold_pen\": false,\n  \"members\": [\n    {\n      \"id\": \"72b37a72-42a5-4529-8cff-928a5db6757e\",\n      \"full_name\": \"Dana Kim\",\n      \"initials\": \"DK\",\n      \"avatar_url\": null,\n      \"email\": \"dana@example.com\",\n      \"role\": \"owner\",\n      \"joined_at\": \"2026-09-15T17:40:30Z\",\n      \"holds_pen\": true\n    },\n    {\n      \"id\": \"2c539862-0ceb-4095-836d-0ebd94711798\",\n      \"full_name\": \"Rob Mills\",\n      \"initials\": \"RM\",\n      \"avatar_url\": null,\n      \"email\": \"rob@example.com\",\n      \"role\": \"member\",\n      \"joined_at\": \"2026-09-15T17:40:30Z\",\n      \"holds_pen\": false\n    }\n  ],\n  \"invites\": [],\n  \"projects\": [\n    {\n      \"id\": \"00e14274-52d0-4a09-a32b-83cba87de735\",\n      \"name\": \"Q4 launch\",\n      \"description\": \"Everything that ships before the quarter closes.\",\n      \"image_url\": null,\n      \"topic_count\": 1\n    }\n  ],\n  \"live_total\": 2,\n  \"waiting\": 0,\n  \"plan\": {\n    \"status\": \"beta\",\n    \"interval\": null,\n    \"current_period_end\": null,\n    \"billing_configured\": false,\n    \"price_month\": 5,\n    \"price_year\": 50,\n    \"locked\": false,\n    \"ending\": false\n  },\n  \"history\": [\n    {\n      \"id\": \"666ff3c2-7722-4bed-aa6b-8884ed60bf86\",\n      \"who\": {\n        \"id\": \"2c539862-0ceb-4095-836d-0ebd94711798\",\n        \"full_name\": \"Rob Mills\",\n        \"initials\": \"RM\",\n        \"avatar_url\": null\n      },\n      \"action\": \"joined the team\",\n      \"subject\": \"Northwind\",\n      \"details\": null,\n      \"at\": \"2026-09-15T17:40:30Z\"\n    },\n    {\n      \"id\": \"e8955d1e-5fe7-494c-b213-eef7059f5b82\",\n      \"who\": {\n        \"id\": \"72b37a72-42a5-4529-8cff-928a5db6757e\",\n        \"full_name\": \"Dana Kim\",\n        \"initials\": \"DK\",\n        \"avatar_url\": null\n      },\n      \"action\": \"invited\",\n      \"subject\": \"rob@example.com\",\n      \"details\": null,\n      \"at\": \"2026-09-15T17:40:30Z\"\n    }\n  ],\n  \"history_more\": false\n}"
            }
          ]
        },
        {
          "name": "A project",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"answers 200\", () => pm.response.to.have.status(200));",
                  "if (pm.response.code < 400) {",
                  "  const project = pm.response.json();",
                  "  if (project.topics.length) pm.collectionVariables.set(\"topic_id\", project.topics[0].id);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/projects/{{project_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "projects",
                "{{project_id}}"
              ]
            },
            "description": ""
          },
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{base_url}}/api/projects/{{project_id}}",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "api",
                    "projects",
                    "{{project_id}}"
                  ]
                },
                "description": ""
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"project\": {\n    \"id\": \"00e14274-52d0-4a09-a32b-83cba87de735\",\n    \"name\": \"Q4 launch\",\n    \"description\": \"Everything that ships before the quarter closes.\",\n    \"image_url\": null\n  },\n  \"team\": {\n    \"id\": \"62c99d17-5c7f-443c-b4ea-46df198b20b5\",\n    \"name\": \"Northwind\",\n    \"initials\": \"N\",\n    \"logo_url\": null\n  },\n  \"you\": \"2c539862-0ceb-4095-836d-0ebd94711798\",\n  \"you_hold_pen\": false,\n  \"is_owner\": false,\n  \"pen\": {\n    \"id\": \"72b37a72-42a5-4529-8cff-928a5db6757e\",\n    \"full_name\": \"Dana Kim\",\n    \"initials\": \"DK\",\n    \"avatar_url\": null\n  },\n  \"members\": [\n    {\n      \"id\": \"72b37a72-42a5-4529-8cff-928a5db6757e\",\n      \"full_name\": \"Dana Kim\",\n      \"initials\": \"DK\",\n      \"avatar_url\": null\n    },\n    {\n      \"id\": \"2c539862-0ceb-4095-836d-0ebd94711798\",\n      \"full_name\": \"Rob Mills\",\n      \"initials\": \"RM\",\n      \"avatar_url\": null\n    }\n  ],\n  \"topics\": [\n    {\n      \"id\": \"e751eacf-7f0c-45f5-a9c5-74b6af8cbf53\",\n      \"name\": \"Revenue\",\n      \"description\": null,\n      \"line\": 5,\n      \"image_url\": null,\n      \"above\": 2,\n      \"below\": 0,\n      \"done\": 0,\n      \"filters\": 1,\n      \"flagged\": 0,\n      \"waiting\": 0\n    }\n  ]\n}"
            }
          ]
        },
        {
          "name": "A topic's ordered list",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"answers 200\", () => pm.response.to.have.status(200));",
                  "if (pm.response.code < 400) {",
                  "  const topic = pm.response.json();",
                  "  if (topic.above.length) pm.collectionVariables.set(\"item_id\", topic.above[0].id);",
                  "  if (topic.filters.length) pm.collectionVariables.set(\"field_id\", topic.filters[0].id);",
                  "  if (topic.suggestions.length) pm.collectionVariables.set(\"suggestion_id\", topic.suggestions[0].id);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/topics/{{topic_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "topics",
                "{{topic_id}}"
              ]
            },
            "description": ""
          },
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{base_url}}/api/topics/{{topic_id}}",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "api",
                    "topics",
                    "{{topic_id}}"
                  ]
                },
                "description": ""
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"topic\": {\n    \"id\": \"e751eacf-7f0c-45f5-a9c5-74b6af8cbf53\",\n    \"name\": \"Revenue\",\n    \"description\": null,\n    \"line\": 5,\n    \"created_at\": \"2026-09-15T17:40:30Z\",\n    \"image_url\": null\n  },\n  \"project\": {\n    \"id\": \"00e14274-52d0-4a09-a32b-83cba87de735\",\n    \"name\": \"Q4 launch\"\n  },\n  \"team\": {\n    \"id\": \"62c99d17-5c7f-443c-b4ea-46df198b20b5\",\n    \"name\": \"Northwind\",\n    \"initials\": \"N\",\n    \"logo_url\": null\n  },\n  \"you\": \"2c539862-0ceb-4095-836d-0ebd94711798\",\n  \"you_hold_pen\": false,\n  \"is_owner\": false,\n  \"pen\": {\n    \"id\": \"72b37a72-42a5-4529-8cff-928a5db6757e\",\n    \"full_name\": \"Dana Kim\",\n    \"initials\": \"DK\",\n    \"avatar_url\": null\n  },\n  \"members\": [\n    {\n      \"id\": \"72b37a72-42a5-4529-8cff-928a5db6757e\",\n      \"full_name\": \"Dana Kim\",\n      \"initials\": \"DK\",\n      \"avatar_url\": null,\n      \"holds_pen\": true,\n      \"joined_at\": \"2026-09-15T17:40:30Z\"\n    },\n    {\n      \"id\": \"2c539862-0ceb-4095-836d-0ebd94711798\",\n      \"full_name\": \"Rob Mills\",\n      \"initials\": \"RM\",\n      \"avatar_url\": null,\n      \"holds_pen\": false,\n      \"joined_at\": \"2026-09-15T17:40:30Z\"\n    }\n  ],\n  \"above\": [\n    {\n      \"id\": \"6d217ccd-7a0e-4e47-99c4-be6b28840a9e\",\n      \"title\": \"Invoice the retainer\",\n      \"reason\": \"It pays **next month's** payroll.\",\n      \"status\": \"open\",\n      \"position\": 1,\n      \"assignee\": null,\n      \"image_url\": null,\n      \"thumb_url\": null,\n      \"stale\": false,\n      \"last_moved_at\": \"2026-09-15T17:40:30Z\",\n      \"created_at\": \"2026-09-15T17:40:30Z\",\n      \"solved_at\": null,\n      \"flag\": null,\n      \"values\": {},\n      \"done_request\": null,\n      \"done_proof\": null\n    },\n    {\n      \"id\": \"aea0d9b2-2ac8-4578-a39f-a2e0fbf5165d\",\n      \"title\": \"Chase the late client\",\n      \"reason\": \"It pays **next month's** payroll.\",\n      \"status\": \"open\",\n      \"position\": 2,\n      \"assignee\": null,\n      \"image_url\": null,\n      \"thumb_url\": null,\n      \"stale\": false,\n      \"last_moved_at\": \"2026-09-15T17:40:30Z\",\n      \"created_at\": \"2026-09-15T17:40:30Z\",\n      \"solved_at\": null,\n      \"flag\": null,\n      \"values\": {},\n      \"done_request\": null,\n      \"done_proof\": null\n    }\n  ],\n  \"below\": [],\n  \"done\": [],\n  \"suggestions\": [],\n  \"filters\": [\n    {\n      \"id\": \"76bd080c-2b7c-46f8-b8f0-60349c60347b\",\n      \"name\": \"Brings money?\",\n      \"kind\": \"yes_no\",\n      \"created_at\": \"2026-09-15T17:40:30Z\",\n      \"born_from\": null\n    }\n  ],\n  \"activity\": [\n    {\n      \"id\": \"575b6335-d0f9-4617-af4d-1aca563c7b5d\",\n      \"who\": {\n        \"id\": \"72b37a72-42a5-4529-8cff-928a5db6757e\",\n        \"full_name\": \"Dana Kim\",\n        \"initials\": \"DK\",\n        \"avatar_url\": null\n      },\n      \"action\": \"put on the list\",\n      \"subject\": \"Chase the late client\",\n      \"details\": \"It pays **next month's** payroll.\",\n      \"at\": \"2026-09-15T17:40:30Z\"\n    },\n    {\n      \"id\": \"3a52aab4-4d88-4a6e-a102-8df9e0c0184c\",\n      \"who\": {\n        \"id\": \"72b37a72-42a5-4529-8cff-928a5db6757e\",\n        \"full_name\": \"Dana Kim\",\n        \"initials\": \"DK\",\n        \"avatar_url\": null\n      },\n      \"action\": \"put on the list\",\n      \"subject\": \"Invoice the retainer\",\n      \"details\": \"It pays **next month's** payroll.\",\n      \"at\": \"2026-09-15T17:40:30Z\"\n    }\n  ],\n  \"activity_more\": false,\n  \"last_ordered_at\": null,\n  \"flagged\": 0,\n  \"park_days\": 30,\n  \"line_min\": 1,\n  \"line_max\": 50\n}"
            }
          ]
        },
        {
          "name": "Assigned to you",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"answers 200\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/assigned",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "assigned"
              ]
            },
            "description": ""
          },
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{base_url}}/api/assigned",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "api",
                    "assigned"
                  ]
                },
                "description": ""
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"items\": [],\n  \"total\": 0\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Anyone on the team",
      "description": "Suggest, flag and request done: what everyone without the pen does.",
      "item": [
        {
          "name": "Suggest an item",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"answers 201\", () => pm.response.to.have.status(201));",
                  "if (pm.response.code < 400) {",
                  "  pm.collectionVariables.set(\"suggestion_id\", pm.response.json().suggestion.id);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/suggestions",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "suggestions"
              ]
            },
            "description": "",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"topic_id\": \"{{topic_id}}\",\n  \"title\": \"Renew the domain\",\n  \"reason\": \"It expires on the **30th**.\",\n  \"assigned_to\": \"{{member_id}}\",\n  \"values\": {\n    \"{{field_id}}\": \"no\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "201 Created",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/api/suggestions",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "api",
                    "suggestions"
                  ]
                },
                "description": "",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"topic_id\": \"{{topic_id}}\",\n  \"title\": \"Renew the domain\",\n  \"reason\": \"It expires on the **30th**.\",\n  \"assigned_to\": \"{{member_id}}\",\n  \"values\": {\n    \"{{field_id}}\": \"no\"\n  }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Created",
              "code": 201,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"suggestion\": {\n    \"id\": \"47ac734d-527a-4202-ac28-6c030198ad62\",\n    \"title\": \"Renew the domain\",\n    \"reason\": \"It expires on the **30th**.\",\n    \"assignee\": {\n      \"id\": \"2c539862-0ceb-4095-836d-0ebd94711798\",\n      \"full_name\": \"Rob Mills\",\n      \"initials\": \"RM\",\n      \"avatar_url\": null\n    },\n    \"by\": {\n      \"id\": \"2c539862-0ceb-4095-836d-0ebd94711798\",\n      \"full_name\": \"Rob Mills\",\n      \"initials\": \"RM\",\n      \"avatar_url\": null\n    },\n    \"created_at\": \"2026-09-15T17:40:31Z\",\n    \"values\": {\n      \"76bd080c-2b7c-46f8-b8f0-60349c60347b\": \"no\"\n    }\n  }\n}"
            }
          ]
        },
        {
          "name": "Ask for another look",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"answers 200\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/priorities/{{item_id}}/flag",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "priorities",
                "{{item_id}}",
                "flag"
              ]
            },
            "description": "",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"note\": \"The client moved the deadline.\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/api/priorities/{{item_id}}/flag",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "api",
                    "priorities",
                    "{{item_id}}",
                    "flag"
                  ]
                },
                "description": "",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"note\": \"The client moved the deadline.\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true\n}"
            }
          ]
        },
        {
          "name": "Request done",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"answers 200\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/priorities/{{item_id}}/request-done",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "priorities",
                "{{item_id}}",
                "request-done"
              ]
            },
            "description": "",
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "note",
                  "value": "Sent and paid on Friday.",
                  "type": "text"
                }
              ]
            }
          },
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "POST",
                "header": [],
                "url": {
                  "raw": "{{base_url}}/api/priorities/{{item_id}}/request-done",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "api",
                    "priorities",
                    "{{item_id}}",
                    "request-done"
                  ]
                },
                "description": "",
                "body": {
                  "mode": "formdata",
                  "formdata": [
                    {
                      "key": "note",
                      "value": "Sent and paid on Friday.",
                      "type": "text"
                    }
                  ]
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Pen holder",
      "description": "These answer 403 unless the token's owner holds the pen on that team.",
      "item": [
        {
          "name": "Add an item",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"answers 201\", () => pm.response.to.have.status(201));",
                  "if (pm.response.code < 400) {",
                  "  pm.collectionVariables.set(\"item_id\", pm.response.json().item.id);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/priorities",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "priorities"
              ]
            },
            "description": "",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"topic_id\": \"{{topic_id}}\",\n  \"title\": \"Plan the offsite\",\n  \"reason\": \"- book the venue\\n- send the agenda\",\n  \"assigned_to\": \"{{member_id}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "201 Created",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/api/priorities",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "api",
                    "priorities"
                  ]
                },
                "description": "",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"topic_id\": \"{{topic_id}}\",\n  \"title\": \"Plan the offsite\",\n  \"reason\": \"- book the venue\\n- send the agenda\",\n  \"assigned_to\": \"{{member_id}}\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Created",
              "code": 201,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"item\": {\n    \"id\": \"73908bca-7f88-4430-a3ea-05b2d708e3af\",\n    \"title\": \"Plan the offsite\",\n    \"reason\": \"- book the venue\\n- send the agenda\",\n    \"status\": \"open\",\n    \"position\": 3,\n    \"assignee\": {\n      \"id\": \"2c539862-0ceb-4095-836d-0ebd94711798\",\n      \"full_name\": \"Rob Mills\",\n      \"initials\": \"RM\",\n      \"avatar_url\": null\n    },\n    \"image_url\": null,\n    \"thumb_url\": null,\n    \"stale\": false,\n    \"last_moved_at\": \"2026-09-15T17:40:31Z\",\n    \"created_at\": \"2026-09-15T17:40:31Z\",\n    \"solved_at\": null,\n    \"flag\": null,\n    \"values\": {},\n    \"done_request\": null,\n    \"done_proof\": null\n  },\n  \"similar\": false\n}"
            }
          ]
        },
        {
          "name": "Move an item",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"answers 200\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/priorities/{{item_id}}/move",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "priorities",
                "{{item_id}}",
                "move"
              ]
            },
            "description": "",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"position\": 1,\n  \"why\": \"The venue fills up.\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/api/priorities/{{item_id}}/move",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "api",
                    "priorities",
                    "{{item_id}}",
                    "move"
                  ]
                },
                "description": "",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"position\": 1,\n  \"why\": \"The venue fills up.\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true\n}"
            }
          ]
        },
        {
          "name": "Finish, or confirm done",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"answers 200\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/priorities/{{item_id}}/done",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "priorities",
                "{{item_id}}",
                "done"
              ]
            },
            "description": ""
          },
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "POST",
                "header": [],
                "url": {
                  "raw": "{{base_url}}/api/priorities/{{item_id}}/done",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "api",
                    "priorities",
                    "{{item_id}}",
                    "done"
                  ]
                },
                "description": ""
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"ok\": true\n}"
            }
          ]
        },
        {
          "name": "Accept a suggestion",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"answers 201\", () => pm.response.to.have.status(201));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/suggestions/{{suggestion_id}}/accept",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "suggestions",
                "{{suggestion_id}}",
                "accept"
              ]
            },
            "description": ""
          },
          "response": [
            {
              "name": "201 Created",
              "originalRequest": {
                "method": "POST",
                "header": [],
                "url": {
                  "raw": "{{base_url}}/api/suggestions/{{suggestion_id}}/accept",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "api",
                    "suggestions",
                    "{{suggestion_id}}",
                    "accept"
                  ]
                },
                "description": ""
              },
              "status": "Created",
              "code": 201,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"item\": {\n    \"id\": \"bcbb1e63-bdf6-44c9-9927-2f624d99e4b5\",\n    \"title\": \"Renew the domain\",\n    \"reason\": \"It expires on the **30th**.\",\n    \"status\": \"open\",\n    \"position\": 3,\n    \"assignee\": {\n      \"id\": \"2c539862-0ceb-4095-836d-0ebd94711798\",\n      \"full_name\": \"Rob Mills\",\n      \"initials\": \"RM\",\n      \"avatar_url\": null\n    },\n    \"image_url\": null,\n    \"thumb_url\": null,\n    \"stale\": false,\n    \"last_moved_at\": \"2026-09-15T17:40:31Z\",\n    \"created_at\": \"2026-09-15T17:40:31Z\",\n    \"solved_at\": null,\n    \"flag\": null,\n    \"values\": {\n      \"76bd080c-2b7c-46f8-b8f0-60349c60347b\": \"no\"\n    },\n    \"done_request\": null,\n    \"done_proof\": null\n  }\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Errors",
      "description": "What a refused call looks like. Every error is JSON with a detail sentence.",
      "item": [
        {
          "name": "A member cannot add",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"answers 403\", () => pm.response.to.have.status(403));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/priorities",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "priorities"
              ]
            },
            "description": "Anyone without the pen gets 403 and suggests instead.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"topic_id\": \"{{topic_id}}\",\n  \"title\": \"Straight on the list\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "403 Forbidden",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{base_url}}/api/priorities",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "api",
                    "priorities"
                  ]
                },
                "description": "Anyone without the pen gets 403 and suggests instead.",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"topic_id\": \"{{topic_id}}\",\n  \"title\": \"Straight on the list\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Forbidden",
              "code": 403,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"detail\": \"Only the person holding the pen adds to the list. Suggest it instead.\"\n}"
            }
          ]
        },
        {
          "name": "An unknown or revoked token",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"answers 401\", () => pm.response.to.have.status(401));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/teams",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "teams"
              ]
            },
            "description": "",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "ph_revoked_or_made_up",
                  "type": "string"
                }
              ]
            }
          },
          "response": [
            {
              "name": "401 Unauthorized",
              "originalRequest": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{base_url}}/api/teams",
                  "host": [
                    "{{base_url}}"
                  ],
                  "path": [
                    "api",
                    "teams"
                  ]
                },
                "description": "",
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "ph_revoked_or_made_up",
                      "type": "string"
                    }
                  ]
                }
              },
              "status": "Unauthorized",
              "code": 401,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"detail\": \"That API token is not valid. It may have been revoked. Create a new one in your profile.\"\n}"
            }
          ]
        }
      ]
    }
  ]
}
