Developers

Built for people
and for agents.

A read-only JSON API, Markdown for every page, and the machine-readable files that describe this site. No key, no signup.

This site is built to be read by people and by software. Everything on this page is public, unauthenticated, and read-only: there is no API key, no signup, and no SDK to install. It works with plain HTTP, with OpenAPI-aware clients, and with agents that call tools from a function schema.

Base URL

All endpoints are relative to https://www.joelcsaji.com and answer over HTTPS only.

Endpoints

MethodPathOperationWhat it returns
GET/api/postslistPostsList published articles
GET/api/posts/{slug}getPostGet one article
GET/api/projectslistProjectsList portfolio projects
GET/api/projects/{id}getProjectGet one project
GET/api/nowgetNowGet the /now snapshot
GET/api/ai-termssearchAiTermsSearch the AI dictionary
GET/api/ai-terms/{slug}getAiTermGet one dictionary entry
GET/api/search-indexgetSearchIndexGet the site search index

The full contract, including parameter and response schemas, is the OpenAPI 3.1 document at /openapi.json. Every operation has a unique operationId, a description, typed parameters, and typed responses, so the document can be loaded directly into function-calling toolchains, API clients, or code generators.

Quickstart

bash
# The newest article
curl -s https://www.joelcsaji.com/api/posts | jq '.items[0]'

# One article, including its Markdown body
curl -s https://www.joelcsaji.com/api/posts/react-19-deep-dive-server-components-compiler-hooks

# Search the AI dictionary
curl -s 'https://www.joelcsaji.com/api/ai-terms?q=agent&maturity=Rising'

# Portfolio projects and case studies
curl -s https://www.joelcsaji.com/api/projects

# The site search index behind the command palette
curl -s https://www.joelcsaji.com/api/search-index

# The current now-page snapshot
curl -s https://www.joelcsaji.com/api/now

# The machine-readable contract
curl -s https://www.joelcsaji.com/openapi.json

List responses have the shape { "items": [...], "total": n }, where n counts everything the filters matched rather than just this page, so a paging client can read total and totalPages without guessing. Single resources are returned as a bare object. Every JSON response carries Access-Control-Allow-Origin: *, so browser-based tools can call the API directly.

Markdown for every page

Every HTML page on this site is also available as Markdown. Send Accept: text/markdown, or fetch the same URL with .md appended, and the response is the page's content without navigation, styles, or scripts:

bash
curl -H 'Accept: text/markdown' https://www.joelcsaji.com/about
curl -s https://www.joelcsaji.com/about.md
curl -H 'Accept: text/markdown' https://www.joelcsaji.com/blog/react-19-deep-dive-server-components-compiler-hooks

Markdown responses use Content-Type: text/markdown; charset=utf-8. Every page response, HTML or Markdown, carries Vary: Accept so caches keep the two apart. Quality values are honoured (text/markdown;q=0.5, text/html still returns HTML), and a client that accepts neither HTML nor Markdown receives 406 Not Acceptable.

Rate limits

Each client may make 60 API requests per 60 seconds. Every API response reports the quota using the IETF RateLimit header fields:

RateLimit-Policy: "default";q=60;w=60
RateLimit: "default";r=59;t=60

q is the quota, w the window in seconds, r the remaining requests, and t the seconds until the window resets. Once the quota is exhausted the API answers 429 Too Many Requests with a Retry-After header in seconds; wait that long and retry. Limits apply per client and are not tied to any account.

Errors

Errors are JSON with the same shape everywhere, including unknown /api/* paths and unsupported methods:

json
{
  "error": {
    "code": "not_found",
    "message": "Post \"nope\" was not found.",
    "hint": "List the available items at https://www.joelcsaji.com/api/posts."
  }
}
StatuscodeWhen
400invalid_parameterA query parameter has an unsupported value; the hint lists accepted values.
404not_foundNo item matches the identifier, or no endpoint exists at the path.
405method_not_allowedOnly GET and HEAD are supported.
429rate_limitedThe quota above was exceeded; honour Retry-After.
500internal_errorSomething failed on the server; retry later.

Machine-readable files

  • /llms.txt: a summary of the site for language models, with guidance on when to use it.
  • /llms-full.txt: the about page, every portfolio case study, and all articles as one Markdown document.
  • /openapi.json: the OpenAPI 3.1 contract for the JSON API.
  • /sitemap.xml: every public URL, with a lastmod date where the content has a real one.
  • /rss.xml: new articles as they publish.
  • /feed.json: the same articles as a JSON Feed 1.1 document.
  • /robots.txt: crawler guidance. Search engines, AI assistants, and agents are welcome.
  • /.well-known/ard.json: the Agentic Resource Discovery catalog listing these endpoints.
  • /.well-known/security.txt: how to report a security issue.

Attribution and contact

Content is written by Joel Saji. Cite the canonical URL of the page you drew from. There is no official CLI or client library; the API is small enough to call directly. Questions, broken responses, or ideas for the API: email hello@joelcsaji.com or use the contact page.

Next step

Building something on this foundation?

Get in touch