Pro plan
Connect your agent
puertafria has an HTTP API and its own MCP server on top of it. Your agent reads the queue, opens a company and records what happened, over HTTPS and never directly against the database. Same rows, same rules, a second door.
Included in Pro, €9 a month, and in Team. On the Free plan the API answers 403 PLAN_API.
# Claude Code, over MCP $ claude mcp add puertafria \ -e PUERTAFRIA_TOKEN=pf_... \ -- npx -y @puertafria/mcp # Any client, over HTTP $ curl -sS https://puertafria.es/api/v1/me \ -H "Authorization: Bearer $PUERTAFRIA_TOKEN"
Four steps
Mint a key
On your account page, under the subscription panel. Give it a label that says where it will be used, and tick the box if it may write, which is off by default. The key is shown once and stored as a hash, so nobody can read it back. Connecting an agent is part of Pro. Go to your account.
Send it as a header
On every request, and nowhere else. Never a query parameter, which a log would keep. Never the session cookie: a signed-in browser must not reach this by accident.
Authorization: Bearer pf_...
Check what the key can do
The first call names the account, the plan, and whether this key may write. An agent that reads it first never discovers a limit by being refused.
curl -sS https://puertafria.es/api/v1/me \ -H "Authorization: Bearer $PUERTAFRIA_TOKEN"
Work the funnel
List the funnels, read the queue, open a company, record what happened. Every call goes through the same function the screen goes through, so it meets the same refusals you do.
curl -sS https://puertafria.es/api/v1/funnels/$FUNNEL/queue \ -H "Authorization: Bearer $PUERTAFRIA_TOKEN"
The MCP server
It runs over stdio as one process your agent host starts, and offers the same tools as the table below. It holds no logic: each tool is one request to those routes, so the API is the remote part and not the shim. A read-only key is offered only read-only tools, rather than finding a 403 by calling something.
One line in Claude Code, with a key from your account. Cursor, Windsurf and Zed run the same npx -y @puertafria/mcp from their own MCP settings, with the key as PUERTAFRIA_TOKEN.
claude mcp add puertafria -e PUERTAFRIA_TOKEN=pf_... \ -- npx -y @puertafria/mcp
Every door, and what is behind it
Paths, tool names and refusals stay English in both languages. A translated path is a wrong path.
Reads
- GET
/api/v1/me - The account this key opens, its plan, and whether this key may change anything.tool: whoami
- GET
/api/v1/funnels - Every funnel this account holds. Start here: nothing else takes a funnel by name.tool: list_funnels
- GET
/api/v1/funnels/:id - One funnel: counts by stage, how many are due, its campaigns and provinces, and its tracking fields with their ids, kinds and options, and its saved views.tool: funnel
- GET
/api/v1/funnels/:id/queue - Who to call today. Takes ?stage= &campaign= &province= &q= &field= &value= (or &from= &to=) &sort= &dir= &page=. A company that asked to stop is never in it.tool: queue
- GET
/api/v1/companies/:id - One card: the row, its branches, its people, its history, its tracking values, its reminders and its email draft, { subject, body, updatedAt } or null.tool: company
- GET
/api/v1/funnels/:id/metrics - One funnel's numbers over ?days=7, 30 or 90. Pro and above; the free plan answers 403 PLAN_METRICS.tool: metrics
- GET
/api/v1/funnels/:id/export/:file - prospects.csv, contacts.csv or activities.csv. For curl and a pipe, never offered as a tool.no tool, on purpose
Writes, and each one needs a key that may write
- PATCH
/api/v1/funnels/:id - A funnel's new name, as { name }. BAD_NAME when blank or too long, NAME_TAKEN when another funnel has it.tool: rename_funnel
- POST
/api/v1/companies/:id/activities - What happened on a call. An outcome that leaves the company open needs nextActionAt; a losing one needs a note.tool: record_outcome
- PATCH
/api/v1/companies/:id/tracking - The funnel's own fields on one company, keyed by field id. A blank clears a value; a field left out is left alone; an unknown id is FIELD_GONE.tool: save_tracking
- PATCH
/api/v1/companies/:id/branches/:locationId/tracking - The funnel's branch fields on one branch of that company. The same rules; a branch of another company is BRANCH_GONE.tool: save_branch_tracking
- PATCH
/api/v1/companies/:id/contacts/:contactId/tracking - The funnel's contact fields on one contact of that company. The same rules; a contact of another company is CONTACT_GONE.tool: save_contact_tracking
- PUT
/api/v1/companies/:id/draft - The company's one email draft, as { subject, body }: at most 200 and 10,000 characters, TOO_LONG past that. An empty body clears it. Never sent by puertafria. SUPPRESSED on a company that asked to stop.tool: save_draft
- POST
/api/v1/companies/:id/reminders - A promise to come back to this company on a day. Pro and above.tool: add_reminder
- PATCH
/api/v1/reminders/:id - Tick a reminder off, put it back, or correct its day or note. One of those per call; what is left out stays.tool: update_reminder
- PATCH
/api/v1/companies/:id/branches/:locationId - One researched fact about one branch of this company. A blank string clears it.tool: edit_branch_fact
- POST
/api/v1/funnels/:id/activate - Move named companies into a campaign. Ids only, never a filter: read the queue first and send what you looked at. One write per company.tool: activate_cohort
- POST
/api/v1/funnels/:id/companies - One company typed in, for when there is no file. Bulk loading is the import screen, not this. A match for a company that asked not to be contacted is SUPPRESSED.tool: add_company
What it will refuse
Nothing deletes. No route removes a company, a funnel, a field or a reminder. An agent stuck in a loop can make a mess you can read, never one that is gone.
A no is forever. A company that asked to stop leaves every queue, and the server refuses another contact against it whoever is asking.
An open outcome has to say when it is picked up again, and a losing one has to carry a note. The same rules the screen obeys.
500 write attempts per key per day. Attempts, not successes: a loop being refused is the loop worth stopping. Activating a cohort spends one per company. Reads never spend.
A key reads only unless you ticked the box, and you revoke it from the same panel. Revoking takes nothing back that it wrote.
The file to point your agent at
Everything on this page, plus the envelope, the refusal words and the rules behind them, in one plain-text address. That is what an agent should read, and it is the whole contract rather than a summary of one.