For agents and developers
Pinpal Projects API and MCP.
The MCP server for assistants, a REST API for your own code, the same sign-in and the same token. A short version for agents is at llms.txt.
Pinpal Projects connector address
https://projects.mypinpal.com/mcpPaste it into Claude or ChatGPT as a custom connector and sign in with Apple or Google. Step by step · API and MCP reference
Two ways in, both supported, with the same sign-in and the same token:
- MCP server:
https://projects.mypinpal.com/mcp. For Claude and every other MCP client. Nothing to install; listed in the MCP Registry ascom.verysimpleprojects/mcp. - REST API:
https://projects.mypinpal.com/api/v1. For your own code, with a token the person pastes from the app (an API key) or one your app gets over OAuth.
A token usually opens exactly one project, and then there is no project parameter. A token for all projects names the project per call (see Authentication). Tickets are numbered 1, 2, 3 per project, the way the person says it. You file, you write in the thread, you attach a screenshot or a log, you change status. You delete only what should never have existed.
Base URL: https://projects.mypinpal.com/api/v1.
Auth: Authorization: Bearer TOKEN.
Short copy: /llms.txt.
Getting started in Claude
Add Pinpal Projects to Claude, and Claude can file tickets, report in the thread and change status in one of your projects.
- In Claude, open Customize, then Connectors.
- Press + and choose Add custom connector.
- Name it Pinpal Projects and paste
https://projects.mypinpal.com/mcp. Press Add. - Press Connect, sign in with Apple or Google, and pick the project Claude may work in, or All my projects.
- Ask Claude something like "file a ticket for the broken login button" or "what is open?".
A connection opens the project you picked. Pick All my projects and Claude can work in every project, asking or being told which one each time; one project is the safer choice. To change it, disconnect and connect again. It works the same in Claude on the web, on desktop and on your phone. Claude plans can add custom connectors, and the free plan allows one. You can see and revoke the connection in the project's settings under Connect.
In Claude Code, add it from the terminal, then run /mcp to sign in and pick the project, or all of them:
claude mcp add --transport http pinpal-projects https://projects.mypinpal.com/mcp
MCP server and tools
Server URL: https://projects.mypinpal.com/mcp (Streamable
HTTP). Any MCP client that supports OAuth connects on its own: a call
without a token answers 401 and points at
/.well-known/oauth-protected-resource,
the client registers itself and sends the person to sign in and pick a
project, or all of them. A token pasted from the app works too, as
Authorization: Bearer TOKEN.
list_projects: only for a connection to all projects; every other tool then takes aproject, by id or name.get_project: the project, its labels, and every status you may set.list_tickets: open, closed, all, or one status, optionally by label.read_ticket: one ticket by number, with its thread.create_ticket: file a ticket with title, body, labels and star.update_ticket: change status with a note, title, body, labels or star.list_commentsandadd_comment: the ticket's thread.read_file: one of the ticket's files by number; a text file comes back as text, a picture as the picture, so Claude can look at a screenshot.attach_file: add a file to the ticket, as text or base64; it gets the next number and a line in the thread.delete_ticket: remove a ticket that should never have existed. It goes to the person's Recently deleted, where they can restore it for 30 days.
The tools follow the same rules as the REST API below: blocked needs a note, and everything works on the free plan except a new ticket past the person's 20 free open tickets.
REST API quickstart
- If you have a
client_id, open the authorize URL. The person signs in and picks the project. You swap the code for a token. - If you do not, they mint a token in that project's Connect list and paste it: an API key that works exactly like the OAuth one.
- Call
GET /api/v1/me. You get the project, the labels you may use, and the statuses. - List open tickets before you file a new one. One ticket per problem. Cancel rather than delete.
curl https://projects.mypinpal.com/api/v1/me \ -H "Authorization: Bearer TOKEN"
Authentication
Bearer token, scoped to one project or to all of them. The person revokes it in the project's settings. Tokens do not expire on their own. Whether it was pasted from the app or minted over OAuth makes no difference.
A token for all projects (offered to every client at connect) names the
project on every call with X-Project: PROJECT_ID.
GET /projects, or GET /me without the header,
lists the projects. A call that needs a project and has none answers
400 project_required.
Authorization: Bearer TOKEN
Pinpal Projects is free for up to 20 open tickets across the person's projects (closed and deleted ones do not count; projects are unlimited). Only filing a ticket past that needs their subscription; it answers 402 with free_limit_reached and a message to relay to the person. Reads, comments, edits, status, star, labels and files always work.
How to behave
- One ticket per distinct problem. List open tickets first and look.
- The report goes in the body. Follow-ups go in comments. A screenshot or a log is attached, not described.
- Title is one line. Not a user story.
blockedneeds a note that is a concrete ask.donewhen the work is finished.deployedonly when it is actually live, not because you pushed.- Use only labels and statuses that
/melists. Never invent one. - Closing is a status. Delete only a ticket that should never have existed, such as a duplicate you just filed.
Statuses
Six are built in and never change: new,
in_progress, blocked, done,
deployed, cancelled. Open is the first three.
The person can add the project's own, like review, each open
or closed. You set those by key like any other, but you cannot make,
rename or delete one; /me lists every key you may set. Any
status may follow any other. A status change with a note is written into
the thread.
GET /me
Connect check: the project, your token's name, labels, statuses.
GET https://projects.mypinpal.com/api/v1/me Authorization: Bearer TOKEN
{
"project": { "id": "…", "name": "Agent Heim", "color": "#F2724B" },
"token": { "name": "Agent Heim · Agnes" },
"labels": [{ "id": "…", "name": "bug", "color": "#8A8178" }],
"statuses": ["new", "in_progress", "blocked", "done", "deployed", "cancelled", "review"],
"open": ["new", "in_progress", "blocked", "review"],
"statusInfo": [{ "key": "new", "name": "New", "color": "#8A8178", "closed": false, "builtIn": true }, …]
}
DELETE /me
Revoke this token. Call it before you store a new one on reconnect.
DELETE https://projects.mypinpal.com/api/v1/me Authorization: Bearer TOKEN
{ "ok": true }
GET /labels
Labels the person has made. You cannot add one from here.
GET https://projects.mypinpal.com/api/v1/labels Authorization: Bearer TOKEN
GET /statuses
Every status in the project, the six built in first, with its name, colour and whether it counts as closed.
GET https://projects.mypinpal.com/api/v1/statuses Authorization: Bearer TOKEN
GET /tickets
Query status=open|closed|all|<status> (default
open), optional label=name. Starred first,
then newest activity.
GET https://projects.mypinpal.com/api/v1/tickets?status=open Authorization: Bearer TOKEN
{
"tickets": [
{
"id": "…",
"number": 12,
"title": "Login sheet stays open",
"preview": "First line of the body",
"status": "in_progress",
"important": false,
"labels": [{ "id": "…", "name": "bug", "color": "#8A8178" }],
"commentCount": 3,
"updatedAt": "2026-09-11T12:00:00.000Z",
"closedAt": null
}
]
}
GET /tickets/:number
One ticket by number, with body and comment thread.
GET https://projects.mypinpal.com/api/v1/tickets/12 Authorization: Bearer TOKEN
POST /tickets
File a ticket. title required. labels is a list
of existing names. Past the free open tickets, without a subscription, this answers 402.
POST https://projects.mypinpal.com/api/v1/tickets
Authorization: Bearer TOKEN
Content-Type: application/json
{ "title": "Login sheet stays open", "body": "## Steps\n1. Tap Continue with Apple", "labels": ["bug"] }
Returns the full ticket with its new number, 201.
PATCH /tickets/:number
Update title, body, status,
note, labels, important.
blocked requires note.
PATCH https://projects.mypinpal.com/api/v1/tickets/12
Authorization: Bearer TOKEN
Content-Type: application/json
{ "status": "blocked", "note": "Needs a TestFlight build." }
DELETE /tickets/:number
Moves the ticket, its whole thread and its files to the person's
Recently deleted. They can restore it in the app for 30 days; after that
it is gone for good. Only the person can restore it or delete it sooner.
For a duplicate you just filed or a test ticket. Work that will not be
done is cancelled, so the trail stays. Comments cannot be
deleted.
DELETE https://projects.mypinpal.com/api/v1/tickets/13 Authorization: Bearer TOKEN
{ "ok": true, "deletedAt": "2026-10-02T09:00:00.000Z", "purgeAt": "2026-11-01T09:00:00.000Z", "message": "..." }
Files
A ticket carries files: a screenshot, a log, a JSON dump. Each gets the
next number in the ticket, never reused, so a person can say "ticket 3,
file 1", and a line in the thread says who attached it.
GET /tickets/:number/files lists them;
GET /tickets/:number/files/:file answers the bytes with their
Content-Type. Attaching takes at most
10 MB, either as multipart/form-data with a file
field or as raw bytes with the type in Content-Type and the
name in X-File-Name. An agent cannot remove a file; the
person does that in the app.
curl https://projects.mypinpal.com/api/v1/tickets/12/files -H "Authorization: Bearer TOKEN" -F file=@before.png
POST https://projects.mypinpal.com/api/v1/tickets/12/files Authorization: Bearer TOKEN Content-Type: text/plain X-File-Name: crash.log (the bytes)
Errors
400bad body, unknown status or label,blockedwithout a note, a file without a name401missing or revoked token402free plan full: a new ticket past the 20 free ones without a subscription ({"error":"free_limit_reached","limit":20,"message":"..."}); relay the message, do not retry404no ticket with that number in this project, no file with that number on it413a file over 10 MB
OAuth 2.0
The person signs in on projects.mypinpal.com and picks the project. Your
server swaps the code for a project token. Discovery:
/.well-known/oauth-authorization-server.
GET https://projects.mypinpal.com/oauth/authorize
?client_id=…
&redirect_uri=…
&response_type=code
&state=…
&code_challenge=…
&code_challenge_method=S256
POST https://projects.mypinpal.com/oauth/token
grant_type=authorization_code
code=…
redirect_uri=…
client_id=…
client_secret=…
code_verifier=…
→ { "access_token": "…", "token_type": "Bearer" }
PKCE S256 is supported. MCP clients and other public apps register
themselves at POST /oauth/register (dynamic client
registration) and must use PKCE S256. Apps with their own server and a
client secret can email
hello@mypinpal.com.
for a client_id. Agent Heim is already registered.
Comments
GET /tickets/:number/commentslists the thread, oldest first.POST /tickets/:number/commentswith{ "body" }adds a follow-up. APATCHwithnote(and no status change) is the same as posting a comment.POST https://projects.mypinpal.com/api/v1/tickets/12/comments Authorization: Bearer TOKEN Content-Type: application/json { "body": "Reproduced on iOS 26.1." }