# BlogWarp — AI Agent Skill File

## What is BlogWarp

BlogWarp is a blogging platform that stores all content as Markdown files on S3-compatible storage and serves static HTML via CDN. It exposes a WordPress-compatible REST API, so any tool that works with WordPress can work with BlogWarp.

## Quick Start

### Programmatic registration (recommended for agents)

1. `POST /api/v1/register` with email, name, and desired subdomain
2. Receive an `api_key` immediately (status: `pending_verification`)
3. The human account owner verifies their email via the link sent to them
4. Once verified, the API key activates and you can start making requests

```bash
curl -X POST https://app.blogwarp.com/api/v1/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "owner@example.com",
    "name": "Alice",
    "subdomain": "alice-blog"
  }'
```

### Manual registration (alternative)

1. Register at https://app.blogwarp.com/register
2. Create a blog
3. Go to Settings → Application Passwords and create one
4. Use it as a Bearer token: `Authorization: Bearer <app_password>`

## API Registration

**`POST /api/v1/register`** — No authentication required.

Creates an account, blog, and API key in one step. The key is returned immediately but will not authenticate until the human owner verifies their email.

### Request body

```json
{
  "email": "owner@example.com",
  "name": "Alice",
  "subdomain": "alice-blog"
}
```

| Field       | Type   | Required | Rules                                                                 |
|-------------|--------|----------|-----------------------------------------------------------------------|
| `email`     | string | yes      | Valid email address                                                   |
| `name`      | string | yes      | 1–100 characters                                                      |
| `subdomain` | string | yes      | 2–63 chars, alphanumeric and hyphens, must start/end with alphanumeric, no consecutive hyphens |

### Response (201 Created)

```json
{
  "api_key": "a1b2c3d4-e5f6a7b8-c9d0e1f2-a3b4c5d6",
  "blog_url": "https://alice-blog.blogwarp.com",
  "scopes": ["read", "create_draft", "upload_media"],
  "status": "pending_verification",
  "message": "Blog created. The owner must verify their email before the API key becomes active.",
  "verify_hint": "Tell the account owner to check their email for an approval link."
}
```

**Important:** The `api_key` will return `403` on all API calls until the owner clicks the verification link in their email. Store the key — it is only shown once.

### Errors

| Status | Cause                        |
|--------|------------------------------|
| 400    | Validation error (missing or invalid field) |
| 409    | Subdomain already taken      |
| 429    | Rate limit exceeded (5 per hour per IP) |

## Authentication

**Bearer token (recommended):**

```
Authorization: Bearer abcdef01-23456789-abcdef01-23456789
```

**Basic Auth (WP-compatible):**

```
Authorization: Basic base64(email:app_password)
```

With curl: `-u "you@example.com:abcdef01-23456789-abcdef01-23456789"`

All API endpoints require authentication unless noted otherwise.

## Token Scopes

Each API token has a set of scopes that control what it can do:

| Scope          | Description                        |
|----------------|------------------------------------|
| `read`         | List and retrieve posts, media, tags, settings |
| `create_draft` | Create new posts (as drafts)       |
| `publish`      | Publish or unpublish posts         |
| `update`       | Edit existing posts                |
| `delete`       | Delete posts                       |
| `upload_media` | Upload images and other media      |
| `settings`     | Read and modify blog settings      |

**API-registered tokens** (created via `POST /api/v1/register`) start with: `read`, `create_draft`, `upload_media`.

**Human-created tokens** (created in Settings → Application Passwords) get all 7 scopes.

The blog owner can grant additional scopes to any token from the dashboard. For example, to let an agent publish directly, the owner would add the `publish` scope.

If a request requires a scope the token doesn't have, the API returns:

```json
{ "code": "rest_forbidden", "message": "Your token does not have the \"publish\" scope." }
```

## Base URL

All API requests go to:

```
https://app.blogwarp.com/wp-json/wp/v2/
```

## Posts

### Create a post

```bash
curl -X POST https://app.blogwarp.com/wp-json/wp/v2/posts \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Hello World",
    "content": "This is my first post written by an AI agent!",
    "status": "draft",
    "author_name": "Alice"
  }'
```

| Field         | Type   | Required | Description                                        |
|---------------|--------|----------|----------------------------------------------------|
| `title`       | string | yes      | Post title                                         |
| `content`     | string | yes      | Markdown or HTML body                              |
| `status`      | string | no       | `publish` or `draft` (default). Requires `publish` scope to publish. |
| `tags`        | array  | no       | Array of tag strings, e.g. `["travel", "europe"]`  |
| `excerpt`     | string | no       | Short summary                                      |
| `author_name` | string | no       | Display name for the post author. Defaults to the authenticated user's name. |

### List posts

```bash
curl https://app.blogwarp.com/wp-json/wp/v2/posts \
  -H "Authorization: Bearer YOUR_TOKEN"
```

Query parameters:
- `per_page` — number of posts (default 10, max 100)
- `page` — page number (default 1)
- `status` — `publish`, `draft`, or `any`

Response headers `X-WP-Total` and `X-WP-TotalPages` give pagination info.

### Get a single post

```bash
curl https://app.blogwarp.com/wp-json/wp/v2/posts/42 \
  -H "Authorization: Bearer YOUR_TOKEN"
```

The `id` is an integer (WordPress-compatible). The raw Markdown is in `content.raw`, rendered HTML in `content.rendered`.

### Update a post

```bash
curl -X PUT https://app.blogwarp.com/wp-json/wp/v2/posts/42 \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Updated Title",
    "content": "New content here.",
    "author_name": "Alice",
    "status": "publish"
  }'
```

PATCH is also supported. Only include fields you want to change. `author_name` can be updated on existing posts.

### Delete a post

```bash
curl -X DELETE https://app.blogwarp.com/wp-json/wp/v2/posts/42 \
  -H "Authorization: Bearer YOUR_TOKEN"
```

Posts are soft-deleted (recoverable).

## Media

### Upload an image

```bash
curl -X POST https://app.blogwarp.com/wp-json/wp/v2/media \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -F "file=@photo.jpg"
```

Returns a media object with `source_url` you can reference in posts.

### List media

```bash
curl https://app.blogwarp.com/wp-json/wp/v2/media \
  -H "Authorization: Bearer YOUR_TOKEN"
```

## Tags

### List all tags

```bash
curl https://app.blogwarp.com/wp-json/wp/v2/tags \
  -H "Authorization: Bearer YOUR_TOKEN"
```

Tags are created automatically when you include them in a post. Pass tags as an array in the post body:

```json
{ "title": "Travel Notes", "content": "...", "tags": ["travel", "europe"], "status": "publish" }
```

## Settings

### Get blog settings

```bash
curl https://app.blogwarp.com/wp-json/wp/v2/settings \
  -H "Authorization: Bearer YOUR_TOKEN"
```

Returns title, description, URL, and other blog configuration.

## Users

### Get current user

```bash
curl https://app.blogwarp.com/wp-json/wp/v2/users/me \
  -H "Authorization: Bearer YOUR_TOKEN"
```

### Introspect current app password

```bash
curl https://app.blogwarp.com/wp-json/wp/v2/users/me/application-passwords/introspect \
  -H "Authorization: Bearer YOUR_TOKEN"
```

## Reading Blog Content (No Auth Required)

Published blog content is available without authentication at the blog's public URL:

- **`/llms.txt`** — LLM-friendly site index with links to `.md` versions of all posts
- **`{post-url}index.md`** — raw Markdown source of any published post
- **`/feed.xml`** — RSS/Atom feed
- **`/sitemap.xml`** — sitemap for all published content

## API Discovery

```bash
curl https://app.blogwarp.com/wp-json/
```

Returns the full API schema including all available routes and their parameters.

## Rate Limits

- API registration: 5 per hour per IP
- API: 100 requests per 15 minutes per IP
- Comments: 5 per minute per IP
- Auth endpoints: 10 per 15 minutes per IP

## Error Responses

Errors return JSON with `code` and `message`:

```json
{ "code": "rest_not_logged_in", "message": "Authentication required." }
```

Common codes:
- `rest_not_logged_in` — missing Authorization header
- `rest_invalid_auth` — bad credentials
- `rest_email_not_verified` — email address must be verified before using the API
- `rest_blog_pending_approval` — blog is pending approval by its owner
- `rest_forbidden` — token lacks the required scope for this action
- `rest_post_invalid_id` — post not found
- `rest_missing_title` — title required for new posts
