Files
Code_of_Conquest/api/docs/API_TESTING.md
2025-11-24 23:10:55 -06:00

39 KiB
Raw Permalink Blame History

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
  2. Authentication Endpoints
  3. Character Endpoints
  4. Testing Workflows
  5. 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

# macOS
brew install httpie

# Ubuntu/Debian
apt-get install httpie

# Python pip
pip install httpie

Start the Application

# 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:

# 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):

{
  "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):

{
  "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):

{
  "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:

# 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):

{
  "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):

{
  "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:

# 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):

{
  "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):

{
  "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:

# 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:

# 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):

{
  "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:

# 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):

{
  "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):

{
  "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:

# 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):

{
  "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):

{
  "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:

# 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):

{
  "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):

{
  "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:

# 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):

{
  "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):

{
  "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):

{
  "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:

# 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):

{
  "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):

{
  "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:

# 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):

{
  "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):

{
  "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):

{
  "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:

# 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):

{
  "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):

{
  "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:

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

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

Success Response (200 OK):

{
  "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:

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

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

Success Response (200 OK):

{
  "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):

{
  "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:

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

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

Success Response (200 OK):

{
  "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):

# 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):

{
  "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):

{
  "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):

# 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):

{
  "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):

{
  "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:

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

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

Success Response (200 OK):

{
  "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:

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

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

Success Response (200 OK):

{
  "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:

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

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

Success Response (200 OK):

{
  "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:

    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:

    http GET "localhost:5000/api/v1/auth/verify-email?userId=XXX&secret=YYY"
    
  4. Login:

    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:

    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:

    http POST localhost:5000/api/v1/auth/reset-password \
      user_id="XXX" \
      secret="YYY" \
      password="NewSecurePass123!"
    
  4. Login with new password:

    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:

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

With authentication:

# 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):

    http --session=user1 POST localhost:5000/api/v1/auth/login \
      email="hero@example.com" \
      password="SecurePass123!"
    
  2. Browse available classes:

    http GET localhost:5000/api/v1/classes
    
  3. Browse available origins:

    http GET localhost:5000/api/v1/origins
    
  4. Create a new character:

    http --session=user1 POST localhost:5000/api/v1/characters \
      name="Thorin Ironforge" \
      class_id="vanguard" \
      origin_id="soul_revenant"
    
  5. View all your characters:

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

    http --session=user1 GET localhost:5000/api/v1/characters/char_123
    
  7. Unlock a skill (when character has skill points from leveling):

    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):

    http --session=user1 POST localhost:5000/api/v1/characters/char_123/skills/respec
    
  9. Delete a character:

    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:

{
  "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:

{
  "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:

{
  "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:

{
  "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:

# 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
# 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

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

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

Verbose Output

# 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)

# 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

# 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

# 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

# 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

# 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