API reference
This site exposes exactly one endpoint: a way to send a message without driving the browser form. It is unauthenticated and free to use. The machine-readable description lives at /openapi.json (OpenAPI 3.1); everything below restates it for humans.
Send a note
POST /api/contact
POST /api/v1/contact
Content-Type: application/json
{
"note": "your message", // required, 1-5000 characters
"email": "you@example.com" // optional reply-to address
} A success returns 200 with { "ok": true }.
No API key is needed. When the site is running with Friendly Captcha
enabled, a third field frcCaptchaResponse is also required,
carrying a token from the widget on the home page; a call without one
answers 400 with captcha_required. That token
can only be produced by a browser, so an automated caller that hits it
should fall back to email.
Versioning and deprecation
The endpoint is available unversioned at /api/contact and
version-pinned at /api/v1/contact. Both serve the same handler
today. Pin to /api/v1/ if you are integrating: breaking changes
will ship under a new path (/api/v2/) rather than altering
v1 in place.
If a version is ever retired it will first return a
Deprecation header and a Sunset header
(RFC 8594)
giving the retirement date, and will keep working for at least six months
after that header first appears. The unversioned path always follows the
newest version and can change without that notice.
Rate limits
Ten requests per hour. Every response to POST /api/contact carries
RateLimit-Limit, RateLimit-Remaining,
RateLimit-Reset and RateLimit-Policy; a
429 adds Retry-After. The limit is enforced per
serving instance rather than globally, so treat it as a floor, not a
guarantee — back off when the headers say to.
Errors
Every error is JSON, never an HTML page, and carries a stable
code you can branch on plus a resolution describing
what to do next:
{
"error": "Note is too long.",
"code": "note_too_long",
"resolution": "Keep `note` to 5000 characters or fewer.",
"status": 400
} | Status | Codes |
|---|---|
| 400 | invalid_body, note_empty, note_too_long, email_invalid, captcha_required, captcha_failed |
| 404 | endpoint_not_found |
| 405 | method_not_allowed |
| 429 | rate_limited |
| 500 | not_configured |
| 502 | delivery_failed — retryable |
CORS
The endpoint and every machine-readable file are served with
Access-Control-Allow-Origin: *, and the endpoint answers
preflight, so a browser-based agent can call it from another origin.
Reading the site itself
There is no read API — the content is published as files instead:
/llms.txt (index and when-to-use guidance),
/llms-full.txt (the home page plus operator
and legal details, in one fetch),
/index.md (the home page as Markdown), and
/sitemap.xml. Requesting / with
Accept: text/markdown returns the Markdown representation.