# API Testing Guide

**Last Updated:** November 15, 2025
**Version:** 0.2.0

This document provides manual testing instructions for Code of Conquest API endpoints.

---

## Table of Contents

1. [Setup](#setup)
2. [Authentication Endpoints](#authentication-endpoints)
3. [Character Endpoints](#character-endpoints)
4. [Testing Workflows](#testing-workflows)
5. [Common Errors](#common-errors)

---

## Setup

### Prerequisites

- **httpie** (recommended) or **curl**
- Flask app running locally (default: `http://localhost:5000`)
- Appwrite configured with valid credentials in `.env`

### Install httpie

```bash
# macOS
brew install httpie

# Ubuntu/Debian
apt-get install httpie

# Python pip
pip install httpie
```

### Start the Application

```bash
# Activate virtual environment
source venv/bin/activate

# Run Flask app
python wsgi.py
```

The app will be available at `http://localhost:5000`

---

## Authentication Endpoints

### 1. Register User

**Endpoint:** `POST /api/v1/auth/register`

**Description:** Create a new user account and trigger email verification.

**Request:**

```bash
# httpie
http POST localhost:5000/api/v1/auth/register \
  email="hero@example.com" \
  password="SecurePass123!" \
  name="Brave Adventurer"

# curl
curl -X POST http://localhost:5000/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "hero@example.com",
    "password": "SecurePass123!",
    "name": "Brave Adventurer"
  }'
```

**Success Response (201 Created):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 201,
  "timestamp": "2025-11-14T12:00:00Z",
  "result": {
    "user": {
      "id": "user_abc123",
      "email": "hero@example.com",
      "name": "Brave Adventurer",
      "email_verified": false,
      "tier": "free",
      "created_at": "2025-11-14T12:00:00Z",
      "updated_at": "2025-11-14T12:00:00Z"
    },
    "message": "Registration successful. Please check your email to verify your account."
  }
}
```

**Error Response (400 Bad Request - Email exists):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 400,
  "timestamp": "2025-11-14T12:00:00Z",
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid input data",
    "details": {
      "email": "An account with this email already exists"
    }
  }
}
```

**Error Response (400 Bad Request - Weak password):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 400,
  "timestamp": "2025-11-14T12:00:00Z",
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid input data",
    "details": {
      "password": "Password must contain at least one uppercase letter, at least one number, at least one special character"
    }
  }
}
```

---

### 2. Login User

**Endpoint:** `POST /api/v1/auth/login`

**Description:** Authenticate user and create session. Sets HTTP-only cookie.

**Request:**

```bash
# httpie (with cookie jar)
http --session=user1 POST localhost:5000/api/v1/auth/login \
  email="hero@example.com" \
  password="SecurePass123!" \
  remember_me:=false

# curl (save cookies)
curl -X POST http://localhost:5000/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -c cookies.txt \
  -d '{
    "email": "hero@example.com",
    "password": "SecurePass123!",
    "remember_me": false
  }'
```

**Success Response (200 OK):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-14T12:00:00Z",
  "result": {
    "user": {
      "id": "user_abc123",
      "email": "hero@example.com",
      "name": "Brave Adventurer",
      "email_verified": true,
      "tier": "free"
    },
    "message": "Login successful"
  }
}
```

**Set-Cookie Header:**

```
Set-Cookie: coc_session=session_xyz789; HttpOnly; Path=/; SameSite=Lax; Max-Age=86400
```

**Error Response (401 Unauthorized):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 401,
  "timestamp": "2025-11-14T12:00:00Z",
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid email or password"
  }
}
```

---

### 3. Logout User

**Endpoint:** `POST /api/v1/auth/logout`

**Description:** Delete user session and clear cookie. Requires authentication.

**Request:**

```bash
# httpie (with saved session)
http --session=user1 POST localhost:5000/api/v1/auth/logout

# curl (with saved cookies)
curl -X POST http://localhost:5000/api/v1/auth/logout \
  -b cookies.txt \
  -c cookies.txt
```

**Success Response (200 OK):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-14T12:00:00Z",
  "result": {
    "message": "Logout successful"
  }
}
```

**Set-Cookie Header (clears cookie):**

```
Set-Cookie: coc_session=; HttpOnly; Path=/; SameSite=Lax; Max-Age=0
```

**Error Response (401 Unauthorized - Not logged in):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 401,
  "timestamp": "2025-11-14T12:00:00Z",
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Authentication required. Please log in."
  }
}
```

---

### 4. Verify Email

**Endpoint:** `GET /api/v1/auth/verify-email?userId=XXX&secret=YYY`

**Description:** Verify user's email address. Called from link in verification email.

**Request:**

```bash
# httpie
http GET "localhost:5000/api/v1/auth/verify-email?userId=user_abc123&secret=verification_secret_xyz"

# curl
curl "http://localhost:5000/api/v1/auth/verify-email?userId=user_abc123&secret=verification_secret_xyz"
```

**Success Response:**

Redirects to `/auth/login` with success flash message.

**Error Response:**

Redirects to `/auth/login` with error flash message.

---

### 5. Request Password Reset

**Endpoint:** `POST /api/v1/auth/forgot-password`

**Description:** Request password reset email. Always returns success for security.

**Request:**

```bash
# httpie
http POST localhost:5000/api/v1/auth/forgot-password \
  email="hero@example.com"

# curl
curl -X POST http://localhost:5000/api/v1/auth/forgot-password \
  -H "Content-Type: application/json" \
  -d '{"email": "hero@example.com"}'
```

**Success Response (200 OK):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-14T12:00:00Z",
  "result": {
    "message": "If an account exists with this email, you will receive a password reset link shortly."
  }
}
```

**Note:** Response is always the same, regardless of whether the email exists (security best practice).

---

### 6. Reset Password

**Endpoint:** `POST /api/v1/auth/reset-password`

**Description:** Confirm password reset with new password. Requires userId and secret from email link.

**Request:**

```bash
# httpie
http POST localhost:5000/api/v1/auth/reset-password \
  user_id="user_abc123" \
  secret="reset_secret_xyz" \
  password="NewSecurePass123!"

# curl
curl -X POST http://localhost:5000/api/v1/auth/reset-password \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": "user_abc123",
    "secret": "reset_secret_xyz",
    "password": "NewSecurePass123!"
  }'
```

**Success Response (200 OK):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-14T12:00:00Z",
  "result": {
    "message": "Password reset successful. You can now log in with your new password."
  }
}
```

**Error Response (400 Bad Request - Invalid/expired link):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 400,
  "timestamp": "2025-11-14T12:00:00Z",
  "error": {
    "code": "PASSWORD_RESET_ERROR",
    "message": "Password reset failed. The link may be invalid or expired."
  }
}
```

---

## Character Endpoints

### 1. Get User's Characters

**Endpoint:** `GET /api/v1/characters`

**Description:** Retrieve all characters belonging to the authenticated user.

**Request:**

```bash
# httpie (with saved session)
http --session=user1 GET localhost:5000/api/v1/characters

# curl (with saved cookies)
curl http://localhost:5000/api/v1/characters -b cookies.txt
```

**Success Response (200 OK):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-15T12:00:00Z",
  "result": {
    "characters": [
      {
        "character_id": "char_123",
        "name": "Thorin Ironforge",
        "class": "vanguard",
        "class_name": "Vanguard",
        "level": 5,
        "experience": 2400,
        "gold": 150,
        "current_location": "forgotten_crypt",
        "origin": "soul_revenant"
      }
    ],
    "count": 1,
    "tier": "free",
    "limit": 1
  }
}
```

**Error Response (401 Unauthorized):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 401,
  "timestamp": "2025-11-14T12:00:00Z",
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Authentication required. Please log in."
  }
}
```

---

### 2. Get Single Character

**Endpoint:** `GET /api/v1/characters/<character_id>`

**Description:** Retrieve detailed information for a specific character. Returns full character data including class, origin, stats, skills, inventory, and equipment.

**Request:**

```bash
# httpie
http --session=user1 GET localhost:5000/api/v1/characters/char_123

# curl
curl http://localhost:5000/api/v1/characters/char_123 -b cookies.txt
```

**Success Response (200 OK):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-15T12:00:00Z",
  "result": {
    "character_id": "char_123",
    "user_id": "user_abc123",
    "name": "Thorin Ironforge",
    "player_class": {
      "class_id": "vanguard",
      "name": "Vanguard",
      "description": "Armored warriors who excel in melee combat...",
      "base_stats": {
        "strength": 14,
        "dexterity": 10,
        "constitution": 14,
        "intelligence": 8,
        "wisdom": 10,
        "charisma": 9
      },
      "skill_trees": [...],
      "starting_equipment": ["Rusty Sword", "Tattered Cloth Armor"],
      "starting_abilities": []
    },
    "origin": {
      "id": "soul_revenant",
      "name": "The Soul Revenant",
      "description": "You died. That much you remember...",
      "starting_location": {
        "id": "forgotten_crypt",
        "name": "The Forgotten Crypt",
        "description": "A crumbling stone tomb..."
      },
      "narrative_hooks": [...],
      "starting_bonus": {
        "type": "stat",
        "value": {"constitution": 1}
      }
    },
    "level": 5,
    "experience": 2400,
    "base_stats": {
      "strength": 16,
      "dexterity": 10,
      "constitution": 14,
      "intelligence": 8,
      "wisdom": 12,
      "charisma": 10
    },
    "unlocked_skills": ["shield_wall", "toughness"],
    "inventory": [],
    "equipped": {},
    "gold": 150,
    "active_quests": [],
    "discovered_locations": ["forgotten_crypt"],
    "current_location": "forgotten_crypt"
  }
}
```

**Error Response (404 Not Found):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 404,
  "timestamp": "2025-11-14T12:00:00Z",
  "error": {
    "code": "CHARACTER_NOT_FOUND",
    "message": "Character not found or you do not have access to it"
  }
}
```

---

### 3. Create Character

**Endpoint:** `POST /api/v1/characters`

**Description:** Create a new character. Subject to tier limits (Free: 1, Basic: 3, Premium: 5, Elite: 10).

**Valid class_id values:** `vanguard`, `assassin`, `arcanist`, `luminary`, `wildstrider`, `oathkeeper`, `necromancer`, `lorekeeper`

**Valid origin_id values:** `soul_revenant`, `memory_thief`, `shadow_apprentice`, `escaped_captive`

**Request:**

```bash
# httpie
http --session=user1 POST localhost:5000/api/v1/characters \
  name="Elara Moonwhisper" \
  class_id="arcanist" \
  origin_id="memory_thief"

# curl
curl -X POST http://localhost:5000/api/v1/characters \
  -H "Content-Type: application/json" \
  -b cookies.txt \
  -d '{
    "name": "Elara Moonwhisper",
    "class_id": "arcanist",
    "origin_id": "memory_thief"
  }'
```

**Success Response (201 Created):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 201,
  "timestamp": "2025-11-15T12:00:00Z",
  "result": {
    "character_id": "char_456",
    "name": "Elara Moonwhisper",
    "class": "arcanist",
    "class_name": "Arcanist",
    "origin": "memory_thief",
    "origin_name": "The Memory Thief",
    "level": 1,
    "gold": 0,
    "current_location": "thornfield_plains",
    "message": "Character created successfully"
  }
}
```

**Error Response (400 Bad Request - Character limit exceeded):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 400,
  "timestamp": "2025-11-14T12:00:00Z",
  "error": {
    "code": "CHARACTER_LIMIT_EXCEEDED",
    "message": "You have reached your character limit for your tier (Free: 1 character)"
  }
}
```

**Error Response (400 Bad Request - Invalid name):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 400,
  "timestamp": "2025-11-14T12:00:00Z",
  "error": {
    "code": "INVALID_INPUT",
    "message": "Character name must be between 2 and 50 characters and contain only letters, numbers, spaces, hyphens, and apostrophes"
  }
}
```

---

### 4. Delete Character

**Endpoint:** `DELETE /api/v1/characters/<character_id>`

**Description:** Soft-delete a character (marks as inactive rather than removing).

**Request:**

```bash
# httpie
http --session=user1 DELETE localhost:5000/api/v1/characters/char_456

# curl
curl -X DELETE http://localhost:5000/api/v1/characters/char_456 \
  -b cookies.txt
```

**Success Response (200 OK):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-14T12:00:00Z",
  "result": {
    "message": "Character deleted successfully"
  }
}
```

**Error Response (404 Not Found):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 404,
  "timestamp": "2025-11-14T12:00:00Z",
  "error": {
    "code": "CHARACTER_NOT_FOUND",
    "message": "Character not found or you do not have access to it"
  }
}
```

---

### 5. Unlock Skill

**Endpoint:** `POST /api/v1/characters/<character_id>/skills/unlock`

**Description:** Unlock a skill for a character. Validates prerequisites, skill points, and tier requirements. Requires 1 skill point (gained per level).

**Request:**

```bash
# httpie
http --session=user1 POST localhost:5000/api/v1/characters/char_123/skills/unlock \
  skill_id="shield_wall"

# curl
curl -X POST http://localhost:5000/api/v1/characters/char_123/skills/unlock \
  -H "Content-Type: application/json" \
  -b cookies.txt \
  -d '{
    "skill_id": "shield_wall"
  }'
```

**Success Response (200 OK):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-15T12:00:00Z",
  "result": {
    "message": "Skill unlocked successfully",
    "character_id": "char_123",
    "skill_id": "shield_wall",
    "unlocked_skills": ["shield_wall"],
    "available_points": 0
  }
}
```

**Error Response (400 Bad Request - Prerequisites not met):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 400,
  "timestamp": "2025-11-14T12:00:00Z",
  "error": {
    "code": "SKILL_UNLOCK_ERROR",
    "message": "Cannot unlock skill: Prerequisites not met (requires: shield_bash)"
  }
}
```

**Error Response (400 Bad Request - Insufficient skill points):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 400,
  "timestamp": "2025-11-14T12:00:00Z",
  "error": {
    "code": "SKILL_UNLOCK_ERROR",
    "message": "Cannot unlock skill: Insufficient skill points (requires: 1, available: 0)"
  }
}
```

---

### 6. Respec Skills

**Endpoint:** `POST /api/v1/characters/<character_id>/skills/respec`

**Description:** Reset all unlocked skills and refund skill points. Costs gold (level × 100 gold).

**Request:**

```bash
# httpie
http --session=user1 POST localhost:5000/api/v1/characters/char_123/skills/respec

# curl
curl -X POST http://localhost:5000/api/v1/characters/char_123/skills/respec \
  -b cookies.txt
```

**Success Response (200 OK):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-15T12:00:00Z",
  "result": {
    "message": "Skills reset successfully",
    "character_id": "char_123",
    "cost": 500,
    "remaining_gold": 100,
    "available_points": 5
  }
}
```

**Error Response (400 Bad Request - Insufficient gold):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 400,
  "timestamp": "2025-11-15T12:00:00Z",
  "error": {
    "code": "INSUFFICIENT_GOLD",
    "message": "Insufficient gold for respec. Cost: 500, Available: 100"
  }
}
```

---

### 7. Get Character Classes

**Endpoint:** `GET /api/v1/classes`

**Description:** Get all available character classes (8 total). No authentication required. Used for character creation UI.

**Request:**

```bash
# httpie
http GET localhost:5000/api/v1/classes

# curl
curl http://localhost:5000/api/v1/classes
```

**Success Response (200 OK):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-15T12:00:00Z",
  "result": {
    "classes": [
      {
        "class_id": "vanguard",
        "name": "Vanguard",
        "description": "Armored warriors who excel in melee combat and protecting allies",
        "base_stats": {
          "strength": 14,
          "dexterity": 10,
          "constitution": 14,
          "intelligence": 8,
          "wisdom": 10,
          "charisma": 9
        },
        "skill_trees": ["Shield Bearer", "Weapon Master"],
        "starting_equipment": ["Rusty Sword", "Tattered Cloth Armor"],
        "starting_abilities": []
      },
      {
        "class_id": "arcanist",
        "name": "Arcanist",
        "description": "Masters of elemental magic, wielding fire and ice",
        "base_stats": {
          "strength": 8,
          "dexterity": 10,
          "constitution": 9,
          "intelligence": 15,
          "wisdom": 12,
          "charisma": 11
        },
        "skill_trees": ["Pyromancy", "Cryomancy"],
        "starting_equipment": ["Worn Staff", "Tattered Cloth Armor"],
        "starting_abilities": []
      }
    ],
    "count": 8
  }
}
```

**Note:** Response includes all 8 classes: vanguard, assassin, arcanist, luminary, wildstrider, oathkeeper, necromancer, lorekeeper

---

### 8. Get Single Character Class

**Endpoint:** `GET /api/v1/classes/<class_id>`

**Description:** Get detailed information about a specific character class including full skill trees. No authentication required. Returns complete skill tree data with 20 skills (2 trees × 5 tiers × 2 nodes).

**Request:**

```bash
# httpie
http GET localhost:5000/api/v1/classes/vanguard

# curl
curl http://localhost:5000/api/v1/classes/vanguard
```

**Success Response (200 OK):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-15T12:00:00Z",
  "result": {
    "class_id": "vanguard",
    "name": "Vanguard",
    "description": "Armored warriors who excel in melee combat and protecting allies",
    "base_stats": {
      "strength": 14,
      "dexterity": 10,
      "constitution": 14,
      "intelligence": 8,
      "wisdom": 10,
      "charisma": 9
    },
    "skill_trees": [
      {
        "tree_id": "shield_bearer",
        "name": "Shield Bearer",
        "description": "Defensive techniques and shield mastery",
        "nodes": [
          {
            "skill_id": "shield_wall",
            "name": "Shield Wall",
            "description": "Increase armor by 5",
            "tier": 1,
            "prerequisites": [],
            "effects": [{"type": "stat", "stat": "armor", "value": 5}]
          }
        ]
      },
      {
        "tree_id": "weapon_master",
        "name": "Weapon Master",
        "description": "Offensive prowess and weapon techniques",
        "nodes": [...]
      }
    ],
    "starting_equipment": ["Rusty Sword", "Tattered Cloth Armor"],
    "starting_abilities": []
  }
}
```

**Error Response (404 Not Found):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 404,
  "timestamp": "2025-11-15T12:00:00Z",
  "error": {
    "code": "NOT_FOUND",
    "message": "Class not found: warrior"
  }
}
```

---

### 9. Get Character Origins

**Endpoint:** `GET /api/v1/origins`

**Description:** Get all available character origins (4 total). No authentication required. Used for character creation UI. Origins provide narrative backstory and starting location.

**Request:**

```bash
# httpie
http GET localhost:5000/api/v1/origins

# curl
curl http://localhost:5000/api/v1/origins
```

**Success Response (200 OK):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-15T12:00:00Z",
  "result": {
    "origins": [
      {
        "id": "soul_revenant",
        "name": "The Soul Revenant",
        "description": "You died. That much you remember. The cold embrace of death, the fading light, the silence. But something—or someone—pulled you back...",
        "starting_location": {
          "id": "forgotten_crypt",
          "name": "The Forgotten Crypt",
          "description": "A crumbling stone tomb beneath a dead forest..."
        },
        "narrative_hooks": [
          "Who or what brought you back from death?",
          "What life did you lead before your demise?",
          "Do fragments of past lives haunt your dreams?"
        ],
        "starting_bonus": {
          "type": "stat",
          "value": {"constitution": 1}
        }
      },
      {
        "id": "memory_thief",
        "name": "The Memory Thief",
        "description": "You awaken with fragments of memories that aren't yours...",
        "starting_location": {
          "id": "thornfield_plains",
          "name": "Thornfield Plains",
          "description": "Endless grasslands dotted with ancient ruins..."
        },
        "narrative_hooks": [
          "Whose memories do you carry?",
          "Why were these memories stolen?"
        ],
        "starting_bonus": {
          "type": "stat",
          "value": {"intelligence": 1}
        }
      }
    ],
    "count": 4
  }
}
```

**Note:** Response includes all 4 origins: soul_revenant, memory_thief, shadow_apprentice, escaped_captive

---

## Game Mechanics Endpoints

### 1. Perform Skill Check

**Endpoint:** `POST /api/v1/game/check`

**Description:** Perform a skill check (persuasion, stealth, perception, etc.) and get deterministic dice roll results. The result includes all dice roll details for UI display and can be passed to AI for narrative description.

**Request (Skill Check - Persuasion):**

```bash
# httpie
http --session=user1 POST localhost:5000/api/v1/game/check \
  character_id="char_123" \
  check_type="skill" \
  skill="persuasion" \
  dc:=15 \
  bonus:=2 \
  context:='{"npc_name": "Guard Captain"}'

# curl
curl -X POST http://localhost:5000/api/v1/game/check \
  -H "Content-Type: application/json" \
  -b cookies.txt \
  -d '{
    "character_id": "char_123",
    "check_type": "skill",
    "skill": "persuasion",
    "dc": 15,
    "bonus": 2,
    "context": {"npc_name": "Guard Captain"}
  }'
```

**Success Response (200 OK - Skill Check Passes):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-23T10:30:00Z",
  "result": {
    "check_result": {
      "roll": 16,
      "modifier": 3,
      "total": 19,
      "dc": 15,
      "success": true,
      "margin": 4,
      "skill_type": "persuasion"
    },
    "context": {
      "skill_used": "persuasion",
      "stat_used": "charisma",
      "npc_name": "Guard Captain"
    }
  }
}
```

**Success Response (200 OK - Skill Check Fails):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-23T10:30:00Z",
  "result": {
    "check_result": {
      "roll": 7,
      "modifier": 1,
      "total": 8,
      "dc": 15,
      "success": false,
      "margin": -7,
      "skill_type": "stealth"
    },
    "context": {
      "skill_used": "stealth",
      "stat_used": "dexterity",
      "situation": "Sneaking past guards"
    }
  }
}
```

---

### 2. Perform Search Action

**Endpoint:** `POST /api/v1/game/check`

**Description:** Perform a search action in a location and get items/gold based on perception check result.

**Request (Search in Forest):**

```bash
# httpie
http --session=user1 POST localhost:5000/api/v1/game/check \
  character_id="char_123" \
  check_type="search" \
  location_type="forest" \
  difficulty="medium" \
  bonus:=0

# curl
curl -X POST http://localhost:5000/api/v1/game/check \
  -H "Content-Type: application/json" \
  -b cookies.txt \
  -d '{
    "character_id": "char_123",
    "check_type": "search",
    "location_type": "forest",
    "difficulty": "medium",
    "bonus": 0
  }'
```

**Success Response (200 OK - Search Succeeds):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-23T10:30:00Z",
  "result": {
    "check_result": {
      "roll": 18,
      "modifier": 2,
      "total": 20,
      "dc": 15,
      "success": true,
      "margin": 5,
      "skill_type": "perception"
    },
    "items_found": [
      {
        "template_key": "ancient_coin",
        "name": "Ancient Coin",
        "description": "A weathered coin from ages past",
        "value": 25
      },
      {
        "template_key": "healing_herb",
        "name": "Healing Herb",
        "description": "A medicinal plant bundle",
        "value": 10
      }
    ],
    "gold_found": 12
  }
}
```

**Success Response (200 OK - Search Fails):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-23T10:30:00Z",
  "result": {
    "check_result": {
      "roll": 4,
      "modifier": 2,
      "total": 6,
      "dc": 15,
      "success": false,
      "margin": -9,
      "skill_type": "perception"
    },
    "items_found": [],
    "gold_found": 0
  }
}
```

---

### 3. Get Available Skills

**Endpoint:** `GET /api/v1/game/skills`

**Description:** Get all available skill types and their associated stats. Used to populate skill selection UI.

**Request:**

```bash
# httpie
http GET localhost:5000/api/v1/game/skills

# curl
curl http://localhost:5000/api/v1/game/skills
```

**Success Response (200 OK):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-23T10:30:00Z",
  "result": {
    "skills": [
      {
        "name": "perception",
        "stat": "wisdom"
      },
      {
        "name": "stealth",
        "stat": "dexterity"
      },
      {
        "name": "persuasion",
        "stat": "charisma"
      },
      {
        "name": "intimidation",
        "stat": "charisma"
      },
      {
        "name": "deception",
        "stat": "charisma"
      },
      {
        "name": "lockpicking",
        "stat": "dexterity"
      },
      {
        "name": "athletics",
        "stat": "strength"
      },
      {
        "name": "acrobatics",
        "stat": "dexterity"
      },
      {
        "name": "sleight_of_hand",
        "stat": "dexterity"
      },
      {
        "name": "arcana",
        "stat": "intelligence"
      },
      {
        "name": "history",
        "stat": "intelligence"
      },
      {
        "name": "investigation",
        "stat": "intelligence"
      },
      {
        "name": "nature",
        "stat": "intelligence"
      },
      {
        "name": "religion",
        "stat": "intelligence"
      },
      {
        "name": "insight",
        "stat": "wisdom"
      },
      {
        "name": "survival",
        "stat": "wisdom"
      },
      {
        "name": "medicine",
        "stat": "wisdom"
      },
      {
        "name": "performance",
        "stat": "charisma"
      },
      {
        "name": "endurance",
        "stat": "constitution"
      }
    ]
  }
}
```

---

### 4. Get Difficulty Levels

**Endpoint:** `GET /api/v1/game/difficulties`

**Description:** Get all difficulty levels and their corresponding DC values. Used to help set appropriate check difficulties.

**Request:**

```bash
# httpie
http GET localhost:5000/api/v1/game/difficulties

# curl
curl http://localhost:5000/api/v1/game/difficulties
```

**Success Response (200 OK):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-23T10:30:00Z",
  "result": {
    "difficulties": [
      {
        "name": "trivial",
        "dc": 5
      },
      {
        "name": "easy",
        "dc": 10
      },
      {
        "name": "medium",
        "dc": 15
      },
      {
        "name": "hard",
        "dc": 20
      },
      {
        "name": "very_hard",
        "dc": 25
      },
      {
        "name": "nearly_impossible",
        "dc": 30
      }
    ]
  }
}
```

---

### 9. Get Character Origins

**Endpoint:** `GET /api/v1/origins`

**Description:** Get all available character origins (4 total). No authentication required. Used for character creation UI. Origins provide narrative backstory and starting location.

**Request:**

```bash
# httpie
http GET localhost:5000/api/v1/origins

# curl
curl http://localhost:5000/api/v1/origins
```

**Success Response (200 OK):**

```json
{
  "app": "Code of Conquest",
  "version": "0.1.0",
  "status": 200,
  "timestamp": "2025-11-15T12:00:00Z",
  "result": {
    "origins": [
      {
        "id": "soul_revenant",
        "name": "The Soul Revenant",
        "description": "You died. That much you remember. The cold embrace of death, the fading light, the silence. But something—or someone—pulled you back...",
        "starting_location": {
          "id": "forgotten_crypt",
          "name": "The Forgotten Crypt",
          "description": "A crumbling stone tomb beneath a dead forest..."
        },
        "narrative_hooks": [
          "Who or what brought you back from death?",
          "What life did you lead before your demise?",
          "Do fragments of past lives haunt your dreams?"
        ],
        "starting_bonus": {
          "type": "stat",
          "value": {"constitution": 1}
        }
      },
      {
        "id": "memory_thief",
        "name": "The Memory Thief",
        "description": "You awaken with fragments of memories that aren't yours...",
        "starting_location": {
          "id": "thornfield_plains",
          "name": "Thornfield Plains",
          "description": "Endless grasslands dotted with ancient ruins..."
        },
        "narrative_hooks": [
          "Whose memories do you carry?",
          "Why were these memories stolen?"
        ],
        "starting_bonus": {
          "type": "stat",
          "value": {"intelligence": 1}
        }
      }
    ],
    "count": 4
  }
}
```

**Note:** Response includes all 4 origins: soul_revenant, memory_thief, shadow_apprentice, escaped_captive

---

## Testing Workflows

### Complete Registration Flow

1. **Register new user:**
   ```bash
   http POST localhost:5000/api/v1/auth/register \
     email="newuser@example.com" \
     password="SecurePass123!" \
     name="New User"
   ```

2. **Check email for verification link**
   - Look for email from Appwrite
   - Extract `userId` and `secret` from verification URL

3. **Verify email:**
   ```bash
   http GET "localhost:5000/api/v1/auth/verify-email?userId=XXX&secret=YYY"
   ```

4. **Login:**
   ```bash
   http --session=newuser POST localhost:5000/api/v1/auth/login \
     email="newuser@example.com" \
     password="SecurePass123!" \
     remember_me:=false
   ```

5. **Verify session is active:**
   - Session cookie should be set
   - Can now access protected routes

---

### Complete Password Reset Flow

1. **Request password reset:**
   ```bash
   http POST localhost:5000/api/v1/auth/forgot-password \
     email="hero@example.com"
   ```

2. **Check email for reset link**
   - Look for email from Appwrite
   - Extract `userId` and `secret` from reset URL

3. **Reset password:**
   ```bash
   http POST localhost:5000/api/v1/auth/reset-password \
     user_id="XXX" \
     secret="YYY" \
     password="NewSecurePass123!"
   ```

4. **Login with new password:**
   ```bash
   http --session=user1 POST localhost:5000/api/v1/auth/login \
     email="hero@example.com" \
     password="NewSecurePass123!" \
     remember_me:=false
   ```

---

### Testing Protected Routes

Protected routes require authentication. Test with and without session cookies.

**Without authentication:**

```bash
# Should return 401 Unauthorized
http POST localhost:5000/api/v1/auth/logout
```

**With authentication:**

```bash
# Login first
http --session=user1 POST localhost:5000/api/v1/auth/login \
  email="hero@example.com" \
  password="SecurePass123!"

# Now can access protected route
http --session=user1 POST localhost:5000/api/v1/auth/logout
```

---

### Complete Character Creation and Management Flow

1. **Login first (required):**
   ```bash
   http --session=user1 POST localhost:5000/api/v1/auth/login \
     email="hero@example.com" \
     password="SecurePass123!"
   ```

2. **Browse available classes:**
   ```bash
   http GET localhost:5000/api/v1/classes
   ```

3. **Browse available origins:**
   ```bash
   http GET localhost:5000/api/v1/origins
   ```

4. **Create a new character:**
   ```bash
   http --session=user1 POST localhost:5000/api/v1/characters \
     name="Thorin Ironforge" \
     class_id="vanguard" \
     origin_id="soul_revenant"
   ```

5. **View all your characters:**
   ```bash
   http --session=user1 GET localhost:5000/api/v1/characters
   ```

6. **View character details (replace char_123 with actual character_id from step 4):**
   ```bash
   http --session=user1 GET localhost:5000/api/v1/characters/char_123
   ```

7. **Unlock a skill (when character has skill points from leveling):**
   ```bash
   http --session=user1 POST localhost:5000/api/v1/characters/char_123/skills/unlock \
     skill_id="shield_wall"
   ```

8. **Respec skills (when needed, costs level × 100 gold):**
   ```bash
   http --session=user1 POST localhost:5000/api/v1/characters/char_123/skills/respec
   ```

9. **Delete a character:**
   ```bash
   http --session=user1 DELETE localhost:5000/api/v1/characters/char_123
   ```

---

## Common Errors

### 400 Bad Request - Validation Error

**Cause:** Invalid input data (email format, weak password, etc.)

**Example:**

```json
{
  "status": 400,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid input data",
    "details": {
      "email": "Invalid email format",
      "password": "Password must be at least 8 characters long"
    }
  }
}
```

**Fix:** Check input validation requirements in error details.

---

### 401 Unauthorized

**Cause:** Not authenticated or invalid session.

**Example:**

```json
{
  "status": 401,
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Authentication required. Please log in."
  }
}
```

**Fix:** Login first and include session cookie with requests.

---

### 409 Conflict - User Already Exists

**Cause:** Email already registered.

**Example:**

```json
{
  "status": 400,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid input data",
    "details": {
      "email": "An account with this email already exists"
    }
  }
}
```

**Fix:** Use a different email or login instead.

---

### 500 Internal Server Error

**Cause:** Server error (Appwrite connection, configuration issue, etc.)

**Example:**

```json
{
  "status": 500,
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "An internal error occurred. Please try again later."
  }
}
```

**Fix:** Check server logs, verify Appwrite credentials, check network connectivity.

---

## Testing Tips

### Using httpie Sessions

httpie sessions persist cookies automatically:

```bash
# Login (saves cookies)
http --session=user1 POST localhost:5000/api/v1/auth/login \
  email="hero@example.com" \
  password="SecurePass123!"

# Subsequent requests automatically include cookies
http --session=user1 POST localhost:5000/api/v1/auth/logout
```

### Using curl Cookie Jar

```bash
# Login (save cookies)
curl -X POST http://localhost:5000/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -c cookies.txt \
  -d '{"email": "hero@example.com", "password": "SecurePass123!"}'

# Use cookies in next request
curl -X POST http://localhost:5000/api/v1/auth/logout \
  -b cookies.txt
```

### Pretty Print JSON

```bash
# httpie (automatic)
http POST localhost:5000/api/v1/auth/register ...

# curl (with jq)
curl ... | jq .
```

### Verbose Output

```bash
# httpie
http -v POST localhost:5000/api/v1/auth/login ...

# curl
curl -v -X POST http://localhost:5000/api/v1/auth/login ...
```

---

---

## Complete Testing Workflow with Game Mechanics

Here's an end-to-end workflow including skill checks and searches:

### 1. Setup (One-time)

```bash
# Register a new user
http POST localhost:5000/api/v1/auth/register \
  email="adventurer@example.com" \
  password="SecurePass123!" \
  name="Brave Adventurer"

# Login and save session
http --session=adventurer POST localhost:5000/api/v1/auth/login \
  email="adventurer@example.com" \
  password="SecurePass123!" \
  remember_me:=false
```

### 2. Create Character

```bash
# Create a character
http --session=adventurer POST localhost:5000/api/v1/characters \
  name="Elara Moonwhisper" \
  class_id="arcanist" \
  origin_id="memory_thief"

# Save the character_id from the response
```

### 3. Get Available Skills and Difficulties

```bash
# Get available skills (before performing checks)
http GET localhost:5000/api/v1/game/skills

# Get difficulty levels
http GET localhost:5000/api/v1/game/difficulties
```

### 4. Perform Skill Checks

```bash
# Attempt persuasion check (charisma-based)
http --session=adventurer POST localhost:5000/api/v1/game/check \
  character_id="<your_character_id>" \
  check_type="skill" \
  skill="persuasion" \
  difficulty="hard" \
  bonus:=1 \
  context:='{"npc_name": "Merchant"}'

# Attempt stealth check (dexterity-based)
http --session=adventurer POST localhost:5000/api/v1/game/check \
  character_id="<your_character_id>" \
  check_type="skill" \
  skill="stealth" \
  dc:=20 \
  bonus:=0

# Attempt arcana check (intelligence-based)
http --session=adventurer POST localhost:5000/api/v1/game/check \
  character_id="<your_character_id>" \
  check_type="skill" \
  skill="arcana" \
  difficulty="medium" \
  bonus:=2
```

### 5. Perform Searches

```bash
# Search in a forest
http --session=adventurer POST localhost:5000/api/v1/game/check \
  character_id="<your_character_id>" \
  check_type="search" \
  location_type="forest" \
  difficulty="easy" \
  bonus:=0

# Search in a cave
http --session=adventurer POST localhost:5000/api/v1/game/check \
  character_id="<your_character_id>" \
  check_type="search" \
  location_type="cave" \
  dc:=13 \
  bonus:=1

# Search in a town
http --session=adventurer POST localhost:5000/api/v1/game/check \
  character_id="<your_character_id>" \
  check_type="search" \
  location_type="town" \
  difficulty="hard" \
  bonus:=2
```

---

## Next Steps

As additional API endpoints are implemented, they will be documented here with:
- Endpoint description
- Request examples (httpie and curl)
- Response examples (success and error cases)
- Testing workflows

Implemented endpoints:
- ✅ Authentication (`/api/v1/auth`)
- ✅ Character management (`/api/v1/characters`)
- ✅ Classes and Origins (`/api/v1/classes`, `/api/v1/origins`)
- ✅ Game Mechanics - Skill Checks and Searches (`/api/v1/game/check`)
- ✅ Game Mechanics - Skills and Difficulties Lists (`/api/v1/game/skills`, `/api/v1/game/difficulties`)

Upcoming endpoints:
- Game sessions (`/api/v1/sessions`)
- Combat (`/api/v1/combat`)
- Marketplace (`/api/v1/marketplace`)
- Shop (`/api/v1/shop`)

---

**Document Version:** 0.3.0
**Created:** November 14, 2025
**Last Updated:** November 23, 2025
