Skip to content

01 / Developers

The Folio API and MCP server.

A REST API over your portfolio. Mint a key in your workspace, then read your profile, outcomes, posts, pages, and more as clean JSON. Grant the key the write scope and the same API creates, updates, and deletes content for you.

Everything is versioned under /api/v1, scoped to your tenant, and documented by a live OpenAPI 3.1 spec you can download below.

Base URL
https://portfolio.wrxstack.com/api/v1
MCP server
https://portfolio.wrxstack.com/api/mcp
Auth
Bearer pk_live_...
Rate limit
60 req / 60s per key
Endpoints
25 routes

02 / Getting started

Three steps to your first response.

  1. 01

    Create an API key

    Open your workspace at /admin and go to Settings > API. The workspace owner mints a key there. The raw key is shown once, so copy it immediately.

  2. 02

    Authenticate

    Send the key as a bearer token on every request: Authorization: Bearer pk_live_... . No cookies, no sessions, no OAuth dance.

  3. 03

    Make your first request

    Call /api/v1/portfolio to pull your entire published portfolio in one response, then narrow to a single resource as you need it.

Your first request
curl https://portfolio.wrxstack.com/api/v1/portfolio \
  -H "Authorization: Bearer pk_live_your_key_here"

03 / Authentication

Keys you mint, scoped to you.

Every request authenticates with a single bearer token. Keys live entirely in your workspace, never expire on us, and only ever reach your own workspace. A key reads by default; writing needs the write scope, granted when you mint it.

How keys work

  • Keys are prefixed pk_live_ and shown once at creation. We store only a SHA-256 hash, never the raw key.
  • Each key is tenant-scoped: it can only reach the workspace that minted it.
  • Keys are read-only unless you choose read and write access when you create them. Writes count against your monthly quota.
  • Rotate or revoke any key from Settings > API at any time. Revoked keys stop working immediately.
  • If you set an expiry, the key stops working after it lapses.

Stay secure

  • Never commit a key to source control or paste it into a client-side bundle.
  • Treat keys as least privilege: one per integration, revoked the moment it is no longer needed.
  • Send keys only over HTTPS, in the Authorization header, never in a query string.
  • Watch the X-RateLimit-* headers and back off on a 429 rather than hammering the API.

04 / MCP server

Your portfolio, inside your AI tools.

Folio hosts a Model Context Protocol server that exposes the v1 API as tools, so Claude, Cursor, VS Code, and other MCP clients can answer questions grounded in your real portfolio and, with a write-scoped key, edit it for you. There is nothing to install: point your client at one URL and send your API key.

Hosted, ready now

One URL. Your API key.

Endpoint (Streamable HTTP)
https://portfolio.wrxstack.com/api/mcp
Header
Authorization: Bearer pk_live_...

With Claude Code it is a single command. Every other client is below.

Claude Code
claude mcp add --transport http folio https://portfolio.wrxstack.com/api/mcp \
  --header "Authorization: Bearer pk_live_your_key_here"

What it does

  • Read everything

    Fetch the entire portfolio in one call, list or read any resource (outcomes, posts, pages, experience, skills, stats, awards, education, testimonials, links), and resolve a single item by slug.

  • Write tools

    Create, update, and delete outcomes, posts, pages, experience, skills, stats, awards, education, testimonials, and links, and update your profile, with folio_create_, folio_update_, and folio_delete_ tools. Writes need a write-scoped key.

  • Same key, same rules

    Tools run through the same v1 endpoints, so the per-key rate limit, monthly quota, and write scope apply exactly as they do to direct requests. A read-only key gets a clear read-only message instead of mutating.

Connect your tools

Folio hosts the MCP server. Point Claude, Cursor, VS Code, or any MCP client at one URL with your API key. Nothing to install.

Endpoint (Streamable HTTP)
https://portfolio.wrxstack.com/api/mcp
Auth header
Authorization: Bearer pk_live_your_key_here

Claude Code

Anthropic terminal agent. Connects to the hosted URL in one command.

Config location

  • Saved by the claude CLI. Local scope by default; add --scope user for every project or --scope project to share via .mcp.json.
TerminalHosted URL
Claude Code command
claude mcp add --transport http folio https://portfolio.wrxstack.com/api/mcp \
  --header "Authorization: Bearer pk_live_your_key_here"

Steps

  1. 1Create an API key under Settings > API. Pick the write scope if you want Claude to edit your portfolio.
  2. 2Run the command below in your terminal, with your real key in place of the placeholder.
  3. 3Start claude (or run /mcp in an open session) so it connects to folio.

Verify

Run claude mcp list: folio should show as connected. In a session, /mcp lists the folio tools. Ask "Summarize my portfolio" to confirm.

Read tools work with any key. Write tools (create, update, delete) need a write-scoped key, and every tool call counts against your workspace monthly quota and the per-key rate limit, exactly like a direct API request.

05 / Endpoint reference

Every route, grouped by resource.

Reads are GET and work with any key. POST, PATCH, and DELETE need a key with the write scope. This table is generated from the live route registry, so it always matches what the API actually serves. Paginated routes accept limit and offset.

Folio v1 API endpoints grouped by resource
MethodPathSummaryAuthPaginated
Portfolio
GET/api/v1/portfolioGet the full published portfolioRequires API keyKeyNo
Profile
GETPATCH/api/v1/profileGet the public profileRequires API keyKeyNo
Outcomes
GETPOST/api/v1/outcomesList published outcomesRequires API keyKeyYes
GETPATCHDELETE/api/v1/outcomes/{slug}Get one outcome by slugRequires API keyKeyNo
Posts
GETPOST/api/v1/postsList published blog postsRequires API keyKeyYes
GETPATCHDELETE/api/v1/posts/{slug}Get one blog post by slugRequires API keyKeyNo
Pages
GETPOST/api/v1/pagesList published custom pagesRequires API keyKeyYes
GETPATCHDELETE/api/v1/pages/{slug}Get one custom page by slugRequires API keyKeyNo
Experience
GETPOST/api/v1/experienceList experience entriesRequires API keyKeyYes
GETPATCHDELETE/api/v1/experience/{id}Get one experience entry by idRequires API keyKeyNo
Skills
GETPOST/api/v1/skillsList skillsRequires API keyKeyYes
GETPATCHDELETE/api/v1/skills/{id}Get one skill by idRequires API keyKeyNo
Stats
GETPOST/api/v1/statsList headline statsRequires API keyKeyYes
GETPATCHDELETE/api/v1/stats/{id}Get one stat by idRequires API keyKeyNo
Awards
GETPOST/api/v1/awardsList awardsRequires API keyKeyYes
GETPATCHDELETE/api/v1/awards/{id}Get one award by idRequires API keyKeyNo
Education
GETPOST/api/v1/educationList education and certificationsRequires API keyKeyYes
GETPATCHDELETE/api/v1/education/{id}Get one education entry by idRequires API keyKeyNo
Testimonials
GETPOST/api/v1/testimonialsList testimonialsRequires API keyKeyYes
GETPATCHDELETE/api/v1/testimonials/{id}Get one testimonial by idRequires API keyKeyNo
Links
GETPOST/api/v1/linksList social and contact linksRequires API keyKeyYes
GETPATCHDELETE/api/v1/links/{id}Get one link by idRequires API keyKeyNo
Meta
GET/api/v1/openapi.jsonDownload the OpenAPI 3.1 document (JSON)Public, no key requiredPublicNo
GET/api/v1/openapi.yamlDownload the OpenAPI 3.1 document (YAML)Public, no key requiredPublicNo
GET/api/v1/postman.jsonDownload a Postman v2.1 collectionPublic, no key requiredPublicNo

Paths shown with {slug} take a URL-safe identifier. Detail routes return 404 when the slug does not resolve.

06 / Conventions

One envelope, predictable errors.

Success response

Collections wrap items in a pagination block. Detail and singleton routes return the item directly under data.

{
  "apiVersion": "v1",
  "tenant": { "slug": "your-workspace", "name": "Your Name" },
  "pagination": { "total": 12, "limit": 20, "offset": 0, "hasMore": false },
  "data": [
    { "slug": "shipped-the-redesign", "title": "Shipped the redesign", "summary": "..." }
  ]
}

Error response

Errors use a stable envelope with a machine-readable code and a human message. The HTTP status matches the code.

{
  "error": {
    "code": "unauthorized",
    "message": "The provided API key is not valid."
  }
}
Folio v1 API error codes
StatusCodeWhen you see it
400bad_requestA query parameter is malformed, e.g. a non-integer limit or offset.
401unauthorizedNo bearer token, or the key is unknown. A WWW-Authenticate challenge is returned.
403forbiddenThe key was revoked or expired, or a write was sent with a key that lacks the write scope.
404not_foundNo published portfolio for the tenant, or the requested slug does not exist.
429rate_limitedThe per-key window was exhausted. A Retry-After header tells you when to retry.
500internal_errorAn unexpected server error. Safe to retry with backoff.

Pagination

Collection routes accept limit (1 to 100, default 20) and offset (a non-negative integer). The pagination block reports total, the echoed limit and offset, and hasMore so you know when to stop paging.

Rate limits

Each key gets 60 requests per 60 second window. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (a Unix timestamp). On a 429 you also get a Retry-After header in seconds.

08 / Build on Folio

Mint a key and start reading.

Create a workspace, publish your portfolio, and generate an API key under Settings > API. Questions about scopes or limits? We are happy to help.