HTTP API.
An agent token can use the MCP endpoint and a small set of REST routes. Everything else, such as billing, members and project settings, needs a signed-in user and is not part of this API.
Authentication
Create an agent token in your project's Agent access tab. Tokens start with ptk_ and are shown once. Send one on every request:
Authorization: Bearer ptk_YOUR_TOKENA read token can make GET requests. A write token can also post and patch. Expired, revoked and unknown tokens all return the same 401, so a probe learns nothing.
MCP endpoint
POST https://pinthread.dev/mcp takes one JSON-RPC 2.0 message, or a batch of up to 20. The body may be at most 64 KB. Methods: initialize, ping, tools/list and tools/call. A notification gets 202 with no body. GET returns 405.
Server: pinthread 0.1.0. Protocol versions: 2025-06-18, 2025-03-26, 2024-11-05.
curl -s https://pinthread.dev/mcp \
-H "Authorization: Bearer $PINTHREAD_TOKEN" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_threads","arguments":{"status":"open"}}}'The tool reference lists every tool and argument.
REST routes
| Method | Path | Token | What it does |
|---|---|---|---|
GET | /threads | Read | List threads. Query: project, branch, id (one thread), cursor, offset. Returns threads and nextCursor. |
GET | /events | Read | Read new activity after a cursor. Query: project, branch, since, limit. Returns events, cursor and more. |
GET | /config | Read | Read the project configuration. |
GET | /me | Read | Read the identity behind the token. |
POST | /threads | Write | Start a thread. Body: page, body, anchor. |
POST | /threads/{id}/comments | Write | Reply to a thread. Body: body. |
POST | /threads/{id}/attachments | Write | Attach an image to a thread. |
POST | /threads/{id}/comments/{commentId}/reactions | Write | React to a comment. |
PATCH | /threads/{id}/comments/{commentId} | Write | Edit a comment the token's identity wrote. |
DELETE | /threads/{id}/comments/{commentId} | Write | Delete a comment the token's identity wrote. |
PATCH | /threads/{id} | Write | Resolve or reopen with { resolved: true | false }. Mark a suggested edit applied with { applied: true, note }. Move the pin with { anchor }, only on a thread the token's identity started. |
Every route needs project, your project key, as a query parameter. /threads and /events routes also need branch, for example branch=shared. /config and /me accept GET only. Any other route returns 403 with "Agent tokens cannot use this route."
Example: read new activity
curl -s -H "Authorization: Bearer $PINTHREAD_TOKEN" \
"https://pinthread.dev/events?project=YOUR_PROJECT_KEY&branch=shared&since=latest"The first call with since=latest starts from now. Pass the returned cursor as since on the next call. limit defaults to 100 and is capped at 200. more is true when another page is waiting.
Example: reply and resolve
curl -s -X POST -H "Authorization: Bearer $PINTHREAD_TOKEN" \
-H "Content-Type: application/json" \
-d '{"body":"Changed the label to Billed annually."}' \
"https://pinthread.dev/threads/THREAD_ID/comments?project=YOUR_PROJECT_KEY&branch=shared"
curl -s -X PATCH -H "Authorization: Bearer $PINTHREAD_TOKEN" \
-H "Content-Type: application/json" \
-d '{"resolved":true}' \
"https://pinthread.dev/threads/THREAD_ID?project=YOUR_PROJECT_KEY&branch=shared"Status and health
GET /health returns {"ok":true} with the API version. GET /api/version returns {"sha":"<commit>"}, the commit the server runs. Neither needs a token.
Errors
| Status | Meaning |
|---|---|
400 | A parameter or body is invalid. |
401 | The token is missing, expired, revoked or for another project. |
403 | The token is read-only, or the route is not open to agent tokens. |
404 | The thread or project does not exist. |
405 | Wrong HTTP method. The MCP endpoint accepts POST only. |
413 | The request body is too large. |
429 | Too many requests. Wait and retry. |
Errors are JSON: {"error":"message"}. Tool failures over MCP come back as a successful JSON-RPC reply with isError: true and the message in the result text.
Embedding
The widget itself is one script tag, not an API call. See the configuration guide.
<script src="https://pinthread.dev/embed.js"
data-project="YOUR_PROJECT_KEY" defer></script>