This site is built to be read by programs as well as people. Public JSON endpoints, an OpenAPI 3.1 contract, Markdown for the main pages and all long-form content, and an MCP manifest. No key, no signup.
Every endpoint is public and CORS-open. Copy any of these:
# Profile as JSON
curl https://www.hirejeffgreen.com/api/profile
# Supported pages as Markdown
curl -H "Accept: text/markdown" https://www.hirejeffgreen.com/about
# Or with a .md suffix
curl https://www.hirejeffgreen.com/blog/some-post.md
# The full contract
curl https://www.hirejeffgreen.com/api/openapi.jsonNone required. There is no API key, token, or signup, and there is nothing to request. Every endpoint is public, read-only (except the contact form), and served with Access-Control-Allow-Origin: * so browser-based agents can call it directly.
| Method | Path | Returns | Description |
|---|---|---|---|
| GET | /api/profile | application/json | Name, title, bio, location, availability, social links. |
| GET | /api/work | application/json | Employment history and featured projects. |
| GET | /api/skills | application/json | Capabilities, technical skills, and the stack this site runs on. |
| GET | /api/contact | application/json | Contact details and the contact-form contract. |
| POST | /api/contact | application/json | Send a message. Sends real email, so only call it on explicit user intent. |
| GET | /api/lab | application/json | Published lab experiments. |
| GET | /api/openapi.json | application/json | The full API contract, OpenAPI 3.1. |
| GET | /blog/{slug}.md | text/markdown | A blog post as Markdown with attribution frontmatter. |
| GET | /work/{slug}.md | text/markdown | A case study as Markdown with attribution frontmatter. |
There is no separate sandbox environment, because there is nothing to protect: the read endpoints are public and idempotent, so production is safe to explore. The API explorer runs live requests against them in the browser. The one exception is POST /api/contact, which sends real email. Treat it as production and only call it on explicit user intent.
Send Accept: text/markdown to any supported page and you get Markdown with attribution frontmatter instead of HTML. Appending .md to the page URL returns byte-identical output — /about.md, /contact.md, /blog/:slug.md, /work/:slug.md, and /index.md for the home page. Responses carry Vary: Accept.
Following the llms.txt v2 proposal, every response advertises where to look next. HTML pages send a Link header with rel="alternate" type="text/markdown" pointing at the Markdown twin, plus rel="describedby" pointing at /llms.txt. Markdown responses send the describedby relation alone. Pages with no Markdown rendition omit the alternate rather than promising a URL that 404s.
A browser Accept header, or */*, always returns HTML. Negotiation never changes what a person sees.
Failures return application/problem+json (RFC 9457) with a stable code you can branch on, a human detail, and a hint describing how to recover. Bodies also carry a top-level error string for older consumers.
| Code | Status | Meaning |
|---|---|---|
| invalid_request | 400 | Malformed request body or headers. |
| validation_failed | 400 | Fields failed validation; see `errors`. |
| not_found | 404 | No such endpoint or resource. |
| method_not_allowed | 405 | Wrong method; see the `Allow` header. |
| not_acceptable | 406 | No representation matches your `Accept`. |
| rate_limited | 429 | Slow down; see `Retry-After`. |
| service_unavailable | 503 | A dependency is down or unconfigured. |
| internal_error | 500 | Unexpected failure. |
POST /api/contact: 5 requests per 1 hour per IP. Exceeding it returns 429 with Retry-After.Breaking changes are announced on this page and in the repository CHANGELOG, with a Deprecation header on affected endpoints for at least the notice period before removal. The notice period is 180 days.