---
title: "Developer and agent documentation"
description: "Public API endpoints, OpenAPI spec, error codes, rate limits, and content negotiation."
canonical: https://www.arpitkhandelwal.com/docs
---
# Developer and agent documentation — Arpit Khandelwal

Machine-readable entry points for arpitkhandelwal.com. Everything below is public, unauthenticated, and returns JSON. Agents should read llms.txt first for when-to-use guidance, then the OpenAPI document for callable operations.

## Entry points

- `/llms.txt` — Site summary and when-to-use guidance for agents.
- `/openapi.json` — OpenAPI 3.1 description of every endpoint (JSON).
- `/api/openapi.yaml` — The same specification in YAML.
- `/api` — Index of the public API with the operation list.
- `/sitemap.xml` — Every indexable URL, with lastmod dates.
- `/robots.txt` — Crawl policy. Every major AI agent is explicitly allowed.

## Endpoints

| Method | Path | Operation | Returns |
| --- | --- | --- | --- |
| GET | /api/profile | getProfile | Identity, location, contact address, profile links, stack |
| GET | /api/availability | getAvailability | Booking status, reply window, sprint lengths and types |
| GET | /api/services | getServices | Focus areas, process, deliverables, terms, good and bad fits |
| GET | /api/work | listWork | Case studies and the project archive |
| GET | /api/faq | listFaq | Published questions and answers |
| POST | /api/contact | createSprintBrief | Delivers a sprint brief; replies within 24 hours |

## Response shape

Success responses are `{ "ok": true, "data": ... }`. Failures are `{ "ok": false, "error": { "code", "message", "hint", "documentation" } }` with an appropriate HTTP status. Branch on `error.code`, which is stable, rather than on the message text.

| Code | Meaning |
| --- | --- |
| `invalid_json` | The request body could not be parsed as JSON. |
| `validation_failed` | A field or query parameter was missing or malformed; see error.details. |
| `method_not_allowed` | The HTTP method is not supported on this path. |
| `not_found` | No such API endpoint. |
| `not_acceptable` | The Accept header excluded every media type this resource can produce. |
| `rate_limited` | Quota exhausted; wait for Retry-After seconds. |
| `delivery_not_configured` | Contact delivery is unavailable; email directly instead. |
| `upstream_failure` | A downstream provider failed; retry once, then email directly. |

## Rate limits

Read endpoints allow 120 requests per 60 seconds per client. POST /api/contact allows 5 per 600 seconds. Every response carries RFC 9331 RateLimit and RateLimit-Policy headers, and a 429 additionally carries Retry-After in seconds. Self-throttle from those headers rather than retrying blindly.

## Example

```bash
curl -s https://www.arpitkhandelwal.com/api/availability

curl -s -X POST https://www.arpitkhandelwal.com/api/contact \
  -H 'content-type: application/json' \
  -d '{"name":"Ada","email":"ada@example.com","message":"We need an MCP server for our internal tools in 4 weeks."}'
```

## Markdown content negotiation

Every page route honours `Accept: text/markdown` and responds with `Vary: Accept`, per acceptmarkdown.com. The same content is also reachable at the `.md` twin of any page path, for example `/about.md`. A request whose `Accept` header excludes both `text/html` and `text/markdown` gets a `406`.
