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_TOKEN

A 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

MethodPathTokenWhat it does
GET/threadsReadList threads. Query: project, branch, id (one thread), cursor, offset. Returns threads and nextCursor.
GET/eventsReadRead new activity after a cursor. Query: project, branch, since, limit. Returns events, cursor and more.
GET/configReadRead the project configuration.
GET/meReadRead the identity behind the token.
POST/threadsWriteStart a thread. Body: page, body, anchor.
POST/threads/{id}/commentsWriteReply to a thread. Body: body.
POST/threads/{id}/attachmentsWriteAttach an image to a thread.
POST/threads/{id}/comments/{commentId}/reactionsWriteReact to a comment.
PATCH/threads/{id}/comments/{commentId}WriteEdit a comment the token's identity wrote.
DELETE/threads/{id}/comments/{commentId}WriteDelete a comment the token's identity wrote.
PATCH/threads/{id}WriteResolve 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

StatusMeaning
400A parameter or body is invalid.
401The token is missing, expired, revoked or for another project.
403The token is read-only, or the route is not open to agent tokens.
404The thread or project does not exist.
405Wrong HTTP method. The MCP endpoint accepts POST only.
413The request body is too large.
429Too 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>