Skip to content

01 / Developers

The Folio API and MCP server.

A read-only REST API over your published portfolio content, plus an MCP server that drops straight into Claude, Cursor, and any MCP client. Mint a key in your workspace, then read your profile, outcomes, posts, pages, and more as clean JSON.

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
Auth
Bearer pk_live_...
Rate limit
60 req / 60s per key
Endpoints
18 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 read your own published data.

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 read the workspace that minted it.
  • 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

Drop your portfolio into any AI client.

folio-mcp is a Model Context Protocol server that wraps every read-only v1 endpoint as an MCP tool. Point it at your key and an assistant can answer questions grounded in your real portfolio. It runs over stdio via npx, so there is nothing to install.

Claude Desktop and Cursor config
{
  "mcpServers": {
    "folio": {
      "command": "npx",
      "args": ["-y", "folio-mcp"],
      "env": {
        "FOLIO_API_KEY": "pk_live_your_key_here",
        "FOLIO_API_BASE_URL": "https://portfolio.wrxstack.com"
      }
    }
  }
}

Add this to your Claude Desktop config (claude_desktop_config.json) or your Cursor MCP settings, then restart the client. The folio-mcp package on npm and its README in the repo mcp-server directory cover advanced options.

Tool overview

  • Portfolio

    Fetch the entire published portfolio in one call so an assistant has full context.

  • Resources

    List or read any single resource: outcomes, posts, pages, experience, skills, stats, awards, education, testimonials, and links.

  • Slugs

    Resolve a single outcome, post, or page by slug for deep, grounded answers.

FOLIO_API_KEY is your workspace key. FOLIO_API_BASE_URL defaults to https://portfolio.wrxstack.com.

05 / Endpoint reference

Every route, grouped by resource.

Every endpoint is a GET. 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
GET/api/v1/profileGet the public profileRequires API keyKeyNo
Outcomes
GET/api/v1/outcomesList published outcomesRequires API keyKeyYes
GET/api/v1/outcomes/{slug}Get one outcome by slugRequires API keyKeyNo
Posts
GET/api/v1/postsList published blog postsRequires API keyKeyYes
GET/api/v1/posts/{slug}Get one blog post by slugRequires API keyKeyNo
Pages
GET/api/v1/pagesList published custom pagesRequires API keyKeyYes
GET/api/v1/pages/{slug}Get one custom page by slugRequires API keyKeyNo
Experience
GET/api/v1/experienceList experience entriesRequires API keyKeyYes
Skills
GET/api/v1/skillsList skillsRequires API keyKeyYes
Stats
GET/api/v1/statsList headline statsRequires API keyKeyYes
Awards
GET/api/v1/awardsList awardsRequires API keyKeyYes
Education
GET/api/v1/educationList education and certificationsRequires API keyKeyYes
Testimonials
GET/api/v1/testimonialsList testimonialsRequires API keyKeyYes
Links
GET/api/v1/linksList social and contact linksRequires API keyKeyYes
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 recognized but has been revoked.
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.

Developer API and MCP | Folio