# Kanaeru AI Developer Portal

Everything a developer - or an AI agent - needs to work with **Kanaeru AI**
programmatically. No sign-up, no API key, no sandbox to provision: the read
endpoints are public and live.

| Resource | URL |
| --- | --- |
| OpenAPI 3.1 spec (JSON) | https://www.kanaeru.ai/openapi.json |
| OpenAPI 3.1 spec (YAML) | https://www.kanaeru.ai/openapi.yaml |
| API index | https://www.kanaeru.ai/api/v1 |
| Official CLI (`kanaeru-cli` on npm) | https://www.npmjs.com/package/kanaeru-cli |
| Agent instructions | https://www.kanaeru.ai/agent-instructions.md |
| llms.txt | https://www.kanaeru.ai/llms.txt |
| Sitemap | https://www.kanaeru.ai/sitemap.xml |
| RSS (English) | https://www.kanaeru.ai/rss.xml |
| Support | support@kanaeru.ai |

## Base URL and versioning

```
https://www.kanaeru.ai/api/v1
```

The API is versioned in the URL path. `/api/v1/...` is the canonical prefix
for every endpoint; the unversioned `/api/...` paths keep working as an alias
for the latest major version. Within `v1`, releases are dated: the current
release is reported as `version` by `GET /api/v1/health`, as `info.version` in
the OpenAPI document, and in the `Kanaeru-Version` header on **every** API
response. Additive changes - new endpoints, new optional fields - bump the
date and never break a caller. Breaking changes only ever ship under a new
prefix (`/api/v2/...`) while `/api/v1` keeps serving.

### Deprecation policy

Nothing is deprecated today. When an endpoint or a major version is scheduled
for removal:

1. It starts answering with a `Deprecation` header ([RFC 9745](https://www.rfc-editor.org/rfc/rfc9745))
   the day the decision is made.
2. A `Sunset` header ([RFC 8594](https://www.rfc-editor.org/rfc/rfc8594))
   names the removal date, **at least 180 days in the future**.
3. The schedule is published on this page.

Until the Sunset date has passed, deprecated surfaces keep working. Agents can
rely on this: a response without a `Deprecation` header is not going away.

## Authentication

**None.** Every read endpoint listed below is public and unauthenticated. There
are no API keys to manage and no OAuth flow.

The two write endpoints (`sendChatMessage`, `submitContactRequest`) are also
unauthenticated, because they are the same endpoints the website's own contact
form and chat widget use. They deliver to real people, so treat them as you would
a "send email" tool: call them only when a user has explicitly asked to contact
Kanaeru AI, and never in a loop.

If you need authenticated, higher-volume or contractual access, email
support@kanaeru.ai and we will set it up.

## Quickstart

Discover the API, then read the catalogue:

```bash
# 1. What endpoints exist?
curl -s https://www.kanaeru.ai/api/v1

# 2. Full machine-readable schema
curl -s https://www.kanaeru.ai/openapi.json

# 3. What services does Kanaeru AI deliver?
curl -s "https://www.kanaeru.ai/api/v1/services?locale=en"

# 4. Show me proof it works
curl -s https://www.kanaeru.ai/api/v1/case-studies

# 5. Read an article as Markdown
curl -s -H "Accept: text/markdown" https://www.kanaeru.ai/blog
```

## Endpoints

### Meta

| Operation | Method & path | Returns |
| --- | --- | --- |
| `getApiIndex` | `GET /api/v1` | Directory of every public endpoint |
| `getHealth` | `GET /api/v1/health` | Liveness and API version |
| `getOpenApiDocument` | `GET /openapi.json` | This API's OpenAPI 3.1 document |

### Catalogue (read-only)

| Operation | Method & path | Returns |
| --- | --- | --- |
| `listServices` | `GET /api/v1/services` | Every service, with slug, category and canonical URL |
| `getService` | `GET /api/v1/services/{slug}` | One service |
| `listCaseStudies` | `GET /api/v1/case-studies` | Delivered projects with measured outcomes |
| `getCaseStudy` | `GET /api/v1/case-studies/{slug}` | One case study |
| `listBlogPosts` | `GET /api/v1/blog-posts` | Engineering articles, newest first |
| `getBlogPost` | `GET /api/v1/blog-posts/{slug}` | One article, including its full Markdown body |

All catalogue endpoints accept `?locale=en` or `?locale=ja`, and the list
endpoints accept `?limit=` (1-100, default 50). `listBlogPosts` also accepts
`?tag=`.

### Contact (writes to a human)

| Operation | Method & path | Effect |
| --- | --- | --- |
| `sendChatMessage` | `POST /api/v1/chat` | Delivers a message to the team, returns a thread id |
| `getChatHistory` | `GET /api/v1/chat-history?sessionId=` | Transcript of an existing session |
| `submitContactRequest` | `POST /api/v1/send-email` | Emails the team a contact request or newsletter signup |

Example:

```bash
curl -s -X POST https://www.kanaeru.ai/api/v1/send-email \
  -H "Content-Type: application/json" \
  -d '{
    "type": "contact",
    "name": "Ada Lovelace",
    "email": "ada@example.com",
    "company": "Analytical Engines Ltd",
    "projectType": "Fixed-price MVP",
    "message": "We need a customer portal delivered in three weeks."
  }'
```

## Error format

Errors are **always JSON**, never an HTML page, on every endpoint and every
status code:

```json
{
  "error": {
    "code": "invalid_request",
    "message": "sessionId is required.",
    "hint": "Pass ?sessionId=<id> as a query parameter.",
    "status": 400,
    "documentation_url": "https://www.kanaeru.ai/developers"
  }
}
```

Branch on `error.code`, not on `error.message` - messages are written for humans
and may be reworded. The codes are stable:

| Code | Status | Meaning |
| --- | --- | --- |
| `invalid_request` | 400 | A parameter or body field is missing or malformed |
| `not_found` | 404 | No such endpoint or resource |
| `method_not_allowed` | 405 | Endpoint exists, method does not. See the `Allow` header |
| `not_acceptable` | 406 | The `Accept` header rejects both `text/html` and `text/markdown` |
| `unsupported_media_type` | 415 | Send the body as `application/json` |
| `rate_limited` | 429 | Back off for the interval in `Retry-After` |
| `service_not_configured` | 503 | A dependency is not configured server-side |
| `upstream_error` | 502 | A downstream provider failed. Retry with backoff |
| `internal_error` | 500 | Unexpected failure. Retry with backoff |

## Rate limits

Per-client quotas, applied by source IP:

| Policy | Endpoints | Quota |
| --- | --- | --- |
| `read` | Catalogue, health, index | 60 requests / 60 s |
| `write` | `POST /api/v1/chat`, `POST /api/v1/send-email` | 10 requests / 60 s |

Every API response reports the quota in standard headers
([draft-ietf-httpapi-ratelimit-headers](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/)),
in both the structured and the widely-parsed legacy form:

```
RateLimit-Policy: "read";q=60;w=60
RateLimit: "read";r=59;t=42
RateLimit-Limit: 60
RateLimit-Remaining: 59
RateLimit-Reset: 42
```

Going over quota answers **429** with the standard JSON error envelope
(`error.code = "rate_limited"`) and a `Retry-After` header giving the seconds
to wait. Self-throttle on `RateLimit-Remaining` and honour `Retry-After` and
you will never be blocked. The write endpoints reach humans - one message per
user intent, never a retry loop. If you need higher or guaranteed throughput,
email support@kanaeru.ai.

## Markdown content negotiation

Every page on this site answers `Accept: text/markdown` with a clean Markdown
representation of the same URL, per [acceptmarkdown.com](https://acceptmarkdown.com/).
Responses carry `Vary: Accept, Accept-Encoding` so a CDN can never hand you the
HTML variant by mistake.

```bash
curl -s -H "Accept: text/markdown" https://www.kanaeru.ai/services/rag-implementation
curl -sI -H "Accept: text/markdown" https://www.kanaeru.ai/ | grep -i -E 'content-type|vary'
```

Appending `.md` to any page URL works too, and is advertised on each page as
`<link rel="alternate" type="text/markdown">`:

```bash
curl -s https://www.kanaeru.ai/blog.md
```

Requesting a path that does not exist returns a real **HTTP 404** with a short
Markdown body pointing at the sitemap, llms.txt and this page - so a lost agent
can recover in one hop instead of guessing.

## Function calling

The OpenAPI document is written to convert directly into LLM tool definitions:
every operation has a unique `operationId`, a `summary`, a prose `description`,
fully typed parameters, and a response schema under `components/schemas`. Point
your framework's OpenAPI-to-tools converter at
`https://www.kanaeru.ai/openapi.json` and the operation ids above become your
tool names.

## Command-line tool (Kanaeru CLI)

**`kanaeru-cli`** is the official command-line client for this API. It ships in
this repository under [`cli/`](https://github.com/kanaerulabs/kanaeru-ai/tree/main/cli),
targets Node.js 18+, has zero runtime dependencies, and installs from npm:

```bash
npm install -g kanaeru-cli

kanaeru services              # every service Kanaeru AI delivers
kanaeru services rag-implementation
kanaeru case-studies          # delivered projects with measured outcomes
kanaeru blog --limit 5        # latest engineering articles
kanaeru blog <slug>           # one article, full Markdown body
kanaeru health                # liveness + current API version
kanaeru openapi               # print the OpenAPI 3.1 document
```

Every command accepts `--locale en|ja` and `--json` (raw API response for
scripting). The CLI is a thin wrapper over the public endpoints above, so
anything it does you can also do with `curl`.

## Developer tooling

**Growth Kit** is our open-source Claude Code plugin that turns a blog post into
social content for X, LinkedIn, Medium and Dev.to. It runs inside Claude Code
with no runtime dependency:

```
/plugin marketplace add kanaerulabs/growth-kit
```

Source: https://github.com/kanaerulabs/growth-kit

## Status and support

There is no separate status page. `GET /api/health` is the liveness signal. For
anything else - bugs, access, higher limits, an integration question - email
**support@kanaeru.ai** and a human replies within one Japan business day.

---

Canonical HTML: https://www.kanaeru.ai/developers
Markdown of any page: send `Accept: text/markdown`, or append `.md` to the URL.
Site index for agents: https://www.kanaeru.ai/llms.txt · API: https://www.kanaeru.ai/openapi.json · Contact: support@kanaeru.ai
