Andrew Campi

Reference / Developers

On this page

Andrew Campi developer resources

This is the developer and agent guide for andrewcampi.com. The site is Andrew Campi's portfolio. It is free to read. There is no API key, no signup, no sandbox tenant, and no paid tier. The only scope is portfolio:read, and every caller already has it. Do not send an Authorization header. A token will not be issued.

robots.txt allows GPTBot, ClaudeBot, ChatGPT-User, PerplexityBot, Google-Extended, and Applebot-Extended, along with every other user agent. A challenge page in front of the host can still stop a crawler before it reads that file. The published intent of this site is that those agents may fetch the public pages.

When to use this

Use these URLs when you need Andrew Campi's current role, the Fiserv dates, or a factual summary of a project written up here (System 1 Server, Cecropia, Vessel, VulnMap, and the rest of the sidebar). Do not use them for Comft or Fiserv product support, account access, or anything that was never published on this domain.

Markdown negotiation

Every documentation URL supports content negotiation on GET.

curl -sS -D - -o /dev/null -H 'Accept: text/markdown' https://andrewcampi.com/
curl -sS -D - -o /dev/null -H 'Accept: text/html' https://andrewcampi.com/

Accept: text/markdown returns a nonempty markdown body with Content-Type: text/markdown; charset=utf-8 and Vary: Accept. Accept: text/html returns the HTML page, also with Vary: Accept. The homepage markdown is the introduction. A project such as https://andrewcampi.com/cecropia.html returns wiki/cecropia.md under the same rule. You can also fetch the files directly:

llms.txt follows the usual shape: an H1, a short blockquote, a "When to use this" section, then links. llms-full.txt is every page concatenated in sidebar order.

JSON API

The API is read-only JSON. The OpenAPI document is https://andrewcampi.com/openapi.json. Protected-resource metadata, including scopes_supported: ["portfolio:read"], is at https://andrewcampi.com/.well-known/oauth-protected-resource. That file does not point at an authorization server. There isn't one.

Method Path operationId Returns
GET /api/v1 getApiDirectory Endpoint list and the public-scope note
GET /api/v1/profile getProfile Name, role, location, education, experience
GET /api/v1/experience getExperience The experience array only
GET /api/v1/projects listProjects Project summaries
GET /api/v1/projects/{slug} getProject One project
curl -sS https://andrewcampi.com/api/v1/profile

Errors are JSON, including 404, 405, and 429:

{
  "error": {
    "code": "not_found",
    "message": "No project named 'missing'.",
    "hint": "GET /api/v1/projects lists every public project slug."
  }
}

Successful responses send RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset. The limit is 120 requests per minute per client IP, counted separately from the MCP endpoint. A 429 also sends Retry-After (seconds) and uses the error code rate_limited. Wait that many seconds and retry the same GET. POST is rejected with method_not_allowed.

Comft's current role is present in the experience array with an empty highlights list. That is intentional. There is no public description of the job yet. Fiserv's end is 2026-06.

Versioning and deprecation

The version is the path prefix /api/v1. How a later version would be retired, including when a response would carry Deprecation and Sunset headers, is written in Andrew Campi API versioning and deprecation policy. /api/v1 is the current version, so those headers are not sent today. Every API response links to that policy with Link: <https://andrewcampi.com/api-versioning.html>; rel="describedby".

Missing pages

A URL that is not a published page, static file, or API route returns HTTP 404. It does not return the homepage. Send Accept: text/markdown and the body is a short markdown explanation that points at llms.txt, this guide, and sitemap.xml. The same pages are also served at extensionless paths: /developers, /docs, /about, /contact, /privacy, and /api-versioning.

MCP

A read-only Model Context Protocol server is at https://andrewcampi.com/mcp. The transport is Streamable HTTP. POST a JSON-RPC 2.0 body. GET returns 405 because this server does not open an SSE side channel. DELETE ends a session with 204. After initialize, the response includes an Mcp-Session-Id header. Later calls may send it back. Calls without it still work.

The discovery files are:

Tools:

  • get_profile reads the same object as GET /api/v1/profile.
  • list_projects reads the project list.
  • get_page takes { "slug": "cecropia" } and returns that page's markdown. Slugs match the HTML file names (work-experience, system1-server, and so on).

Each tool is marked read-only. None of them change the site.

What this site does not publish

There is no official portfolio CLI on npm, PyPI, or Homebrew. Natural and Otto are separate projects, not clients for this domain. There is no OAuth authorization server, no API key screen, and no trial signup. The sitemap of the HTML pages is https://andrewcampi.com/sitemap.xml.