# YWD CMS API Reference

Base URL: `/api/v1`

All responses are JSON. Read endpoints return `200`, create endpoints return `201`, validation failures return `422`, missing records return `404`, and throttled requests return `429`.

## Rate Limits

| Endpoint group | Limit |
|---|---|
| `POST /auth/token` | 10 requests / minute |
| Read endpoints (`GET`) | 60 requests / minute |
| Write endpoints (`POST`) | 30 requests / minute |

## Health Check

`GET /api/health`

Response:

```json
{ "status": "ok" }
```

## Authentication

The API exposes token issuance at `POST /api/v1/auth/token`.

Request body:

```json
{
  "email": "admin@example.com",
  "password": "secret123",
  "device_name": "browser"
}
```

Response:

```json
{
  "token": "generated-token",
  "token_type": "Bearer",
  "user": {
    "id": 1,
    "name": "Admin",
    "email": "admin@example.com",
    "role": "admin"
  }
}
```

Use the token as `Authorization: Bearer <token>` when an endpoint expects authenticated API access.

## Content Endpoints

- `GET /api/v1/posts`
- `GET /api/v1/posts/{slug}`
- `GET /api/v1/pages/{slug}`
- `GET /api/v1/categories`
- `GET /api/v1/tags`
- `GET /api/v1/media`
- `GET /api/v1/menus/{location}`
- `GET /api/v1/settings`
- `POST /api/v1/comments`

## Posts

`GET /api/v1/posts` supports:

- `category`
- `tag`
- `search`
- `page`
- `per_page`

Response shape:

```json
{
  "data": [
    {
      "id": 1,
      "title": "Hello World",
      "slug": "hello-world",
      "excerpt": "Short summary",
      "featured_image": "/uploads/example.jpg",
      "published_at": "2026-06-15 10:00:00",
      "author": { "id": 1, "name": "Admin" },
      "categories": [],
      "tags": []
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 1,
    "per_page": 15,
    "total": 1
  }
}
```

`GET /api/v1/posts/{slug}` returns the full post payload, including `content` and `comments_count`.

## Pages

`GET /api/v1/pages/{slug}` returns one published page by slug.

## Taxonomy and Settings

- `GET /api/v1/categories` returns the available categories.
- `GET /api/v1/tags` returns the available tags.
- `GET /api/v1/settings` returns public settings exposed by the application.
- `GET /api/v1/menus/{location}` returns the menu for a given location.

## Comments

`POST /api/v1/comments` accepts:

```json
{
  "post_id": 1,
  "content": "Great post",
  "author_name": "Guest User",
  "author_email": "guest@example.com",
  "parent_id": null,
  "website": ""
}
```

Notes:

- `author_name` and `author_email` are required for guests.
- The hidden `website` field is used as a honeypot and should stay empty.
- New comments are created with `pending` status.

## Source of Truth

The route map lives in [src/routes.php](src/routes.php). If routes change, update this file together with the code.
