# API v1

The JSON API is mounted at `/api/v1`. It is base-path aware: on a subdirectory install the prefix is `/{base}/api/v1`.

All responses are JSON. Errors carry a stable machine code — see [Error codes](ERROR-CODES.md).

## Authentication

Send a bearer token:

```
Authorization: Bearer <token>
```

Tokens are managed by the member under account settings. See [Auth tokens](AUTH-TOKENS.md).

Read endpoints that expose only public content work without a token. Every mutation requires one.

## Endpoints

### Questions

| Method | Path | Purpose |
|---|---|---|
| `GET` | `/questions` | List published questions; supports filtering and pagination |
| `POST` | `/questions` | Create a question |
| `GET` | `/questions/{idOrSlug}` | Fetch one question with its answers |
| `POST` | `/questions/{id}/answers` | Post an answer |
| `POST` | `/questions/{id}/comments` | Comment on a question |
| `POST` | `/questions/{id}/accept` | Accept an answer (body carries `answer_id`) |

### Answers

| Method | Path | Purpose |
|---|---|---|
| `POST` | `/answers/{id}/comments` | Comment on an answer |
| `POST` | `/answers/{id}/accept` | Accept that answer |

### Member surfaces

| Method | Path | Purpose |
|---|---|---|
| `GET` | `/me` | The authenticated member |
| `GET` | `/notifications` | The authenticated member's notifications |

### Community actions

| Method | Path | Purpose |
|---|---|---|
| `POST` | `/votes` | Cast a vote |
| `POST` | `/follows` | Follow or unfollow a target (`target_type` accepts `question`, `topic`, `category`, `tag`) |
| `POST` | `/reports` | Report content |

### Reserved

`/comments` and the `/auth/*` routes are reserved. They answer `501 not_implemented` until their contracts are finalised — they are deliberately not silent 404s, so a client can tell "not yet" from "never".

## Method handling

A known path with the wrong method answers `405` and advertises the methods it accepts. An unknown path answers `404 route_not_found`.

## Rate limiting

Mutations are rate limited per account and per address. Exceeding a limit answers `429 rate_limited`.

## Content

Bodies are Markdown, exactly like the web forms. The server renders and sanitises. Posting raw HTML does not produce raw HTML output.

## Errors

Failures answer with a status code and a stable code:

```json
{ "error": { "code": "invalid_request", "message": "…" } }
```

Messages are translated; codes are not. Branch on the code, display the message.
