# PointStack Agent API PointStack is real-time planning poker. This is the complete HTTP API for AI agents and scripts to create and manage estimation rooms. Base URL: https://pointstack.dev A typical flow: create a room (optionally with a backlog of stories), share the returned URL with your team, and they vote. The first person to join a tokenless room becomes its owner. ## Further reading - https://pointstack.dev/llms/workflows.txt — step-by-step recipes (the "put up these tickets" flow, editing a backlog, acting for a user, polling). - https://pointstack.dev/llms/errors.txt — every error code, how to recover, and how to guide the user when something fails. - https://pointstack.dev/llms/responding.txt — how to phrase replies to the user (room-link handoff, "join first to claim", token prompts) with copy-paste message templates. ## Authentication Three modes, sent as `Authorization: Bearer `: - No token: only `POST /api/v1/rooms` is allowed. It creates a *headless* room (no owner) that the first voter to join Claims as owner. Tokenless creation is rate-limited and may be temporarily unavailable under load (HTTP 503) — fall back to a user token or retry. - Room token (`psr_…`): returned once when a room is created. Grants full read/write/delete on that one room, indefinitely (until the owner revokes it in room settings). - User token (`psk_…`): a user generates one on their Account page. Acts as that user: create rooms and read/write/delete any room they own, and set a room's team. Works until rotated/revoked. ## Limits - Story title: 150 chars. Story details: 20,000 chars. Link: 500 chars. - Up to 200 stories per room, 50 stories per request. - A room holds up to 20 connected participants. - Agents cannot set estimates — estimates come from people voting in the room. ## Errors All errors share this shape; `code` is stable, `hint` tells you how to recover: ```json { "error": { "code": "rate_limited", "message": "…", "hint": "…", "docs": "/llms.txt", "retryAfter": 30 } } ``` Codes: `unauthorized` (401), `forbidden` (403), `not_found` (404), `validation_failed` (400), `rate_limited` (429), `tokenless_unavailable` (503), `room_full` (409). `retryAfter` (seconds) is present on 429/503. ## Endpoints ### POST /api/v1/rooms — create a room No token → headless room. `Bearer psk_…` → room owned by you. Body (all optional except story titles): ```json { "name": "Sprint 42", "deck": "fibonacci", "customCards": ["1","2","3"], "autoReveal": false, "allowGuests": true, "teamId": "team_…", "stories": [ { "title": "Login flow", "details": "markdown…", "nameLink": "https://github.com/org/repo/issues/1" } ] } ``` Decks: `fibonacci`, `modified-fibonacci`, `tshirt`, `powers-of-2`, or `custom` (requires `customCards`). `name` defaults to "Room ". `teamId` requires a user token and team membership. `nameLink` is the URL a story's title points to (if the title itself is a URL, it becomes the link automatically). Response 201: ```json { "id": "…", "code": "ABC123", "url": "https://pointstack.dev/room/ABC123", "roomToken": "psr_…", "owner": null, "expiresAt": "2026-01-01T12:00:00.000Z", "stories": [ { "id": "…", "title": "Login flow", "nameLink": "https://…" } ] } ``` `roomToken` is shown only once — store it. `owner` is null until the room is claimed. `expiresAt` is when an unclaimed room is swept (null once claimed). Example: ```sh curl -X POST https://pointstack.dev/api/v1/rooms \ -H 'content-type: application/json' \ -d '{"name":"Sprint 42","stories":[{"title":"Login flow","nameLink":"https://github.com/org/repo/issues/1"}]}' ``` ### GET /api/v1/rooms/:id — read a room Auth: room or user token. Returns settings, stories (with `nameLink`, status, finalEstimate), live `phase`/`currentStoryId`, and participants. ```sh curl https://pointstack.dev/api/v1/rooms/ROOM_ID -H 'authorization: Bearer psr_…' ``` ### PATCH /api/v1/rooms/:id — update settings Provided fields only: `name`, `deck`, `autoReveal`, `allowGuests`, `teamId` (user token only). Applies live to anyone in the room. ```sh curl -X PATCH https://pointstack.dev/api/v1/rooms/ROOM_ID \ -H 'authorization: Bearer psr_…' -H 'content-type: application/json' \ -d '{"name":"Renamed","autoReveal":true}' ``` ### DELETE /api/v1/rooms/:id — delete (archive) the room Disconnects participants and removes the room. ### POST /api/v1/rooms/:id/stories — add stories Body: `{ "stories": [ { "title": "…", "details": "…", "nameLink": "…" } ] }` (or a single `{ "title": … }`). Returns the created stories with their ids. ### PATCH /api/v1/rooms/:id/stories/:storyId — update a story Body: any of `title`, `details`, `nameLink` (send `null` to clear the link). Never affects votes/phase. Omitted fields are left unchanged. ### DELETE /api/v1/rooms/:id/stories/:storyId — delete a story Removes it regardless of state; if it was the active round, the round ends.