Files
Code_of_Conquest/api/docs/API_REFERENCE.md

2214 lines
46 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# API Reference
All API responses follow standardized format:
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-27T12:00:00Z",
"request_id": "optional-request-id",
"result": {},
"error": null,
"meta": {}
}
```
**Base URL:** `/api/v1`
---
## Authentication
Authentication handled by Appwrite with HTTP-only cookies. Sessions are stored in `coc_session` cookie.
**Cookie Configuration:**
- **Name:** `coc_session`
- **HTTP-only:** true (JavaScript cannot access)
- **Secure:** true (HTTPS only in production)
- **SameSite:** Lax (CSRF protection)
- **Duration (normal):** 24 hours
- **Duration (remember me):** 30 days
**Session Caching:**
Sessions are cached in Redis (db 2) to reduce Appwrite API calls by ~90%. Cache TTL is 5 minutes. Sessions are explicitly invalidated on logout and password change.
### Register
| | |
|---|---|
| **Endpoint** | `POST /api/v1/auth/register` |
| **Description** | Create new user account with email verification |
| **Auth Required** | No |
**Request Body:**
```json
{
"email": "player@example.com",
"password": "SecurePass123!",
"name": "Adventurer"
}
```
**Response (201 Created):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 201,
"timestamp": "2025-11-14T12:00:00Z",
"result": {
"user": {
"id": "user_id_123",
"email": "player@example.com",
"name": "Adventurer",
"email_verified": false,
"tier": "free",
"created_at": "2025-11-14T12:00:00Z"
},
"message": "Registration successful. Please check your email to verify your account."
}
}
```
### Login
| | |
|---|---|
| **Endpoint** | `POST /api/v1/auth/login` |
| **Description** | User login with session cookie |
| **Auth Required** | No |
**Request Body:**
```json
{
"email": "player@example.com",
"password": "SecurePass123!",
"remember_me": true
}
```
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-14T12:00:00Z",
"result": {
"user": {
"id": "user_id_123",
"email": "player@example.com",
"name": "Adventurer",
"email_verified": true,
"tier": "free"
},
"message": "Login successful"
}
}
```
**Set-Cookie Header:**
```
Set-Cookie: coc_session=<session_token>; HttpOnly; Secure; SameSite=Lax; Max-Age=2592000; Path=/
```
### Logout
| | |
|---|---|
| **Endpoint** | `POST /api/v1/auth/logout` |
| **Description** | Logout current session and clear cookie |
| **Auth Required** | Yes |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-14T12:00:00Z",
"result": {
"message": "Logout successful"
}
}
```
### Get Current User
| | |
|---|---|
| **Endpoint** | `GET /api/v1/auth/me` |
| **Description** | Get current authenticated user's data |
| **Auth Required** | Yes |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-14T12:00:00Z",
"result": {
"id": "user_id_123",
"email": "player@example.com",
"name": "Adventurer",
"email_verified": true,
"tier": "premium"
}
}
```
### Verify Email
| | |
|---|---|
| **Endpoint** | `GET /api/v1/auth/verify-email` |
| **Description** | Verify user email address |
| **Auth Required** | No |
**Query Parameters:**
- `userId` - User ID from verification email
- `secret` - Verification secret from email
**Success:** Redirects to `/auth/login?verified=true`
**Error:** Redirects to `/auth/login?verified=false`
### Forgot Password
| | |
|---|---|
| **Endpoint** | `POST /api/v1/auth/forgot-password` |
| **Description** | Request password reset email |
| **Auth Required** | No |
**Request Body:**
```json
{
"email": "player@example.com"
}
```
**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."
}
}
```
### Reset Password
| | |
|---|---|
| **Endpoint** | `POST /api/v1/auth/reset-password` |
| **Description** | Submit new password |
| **Auth Required** | No |
**Request Body:**
```json
{
"user_id": "user_id_123",
"secret": "reset_secret",
"password": "NewSecurePass123!"
}
```
**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."
}
}
```
---
## Characters
### List Characters
| | |
|---|---|
| **Endpoint** | `GET /api/v1/characters` |
| **Description** | Get all characters for current user with tier information |
| **Auth Required** | Yes |
**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 Ironheart",
"class": "vanguard",
"class_name": "Vanguard",
"level": 5,
"experience": 250,
"gold": 1000,
"current_location": "forgotten_crypt",
"origin": "soul_revenant"
}
],
"count": 1,
"tier": "free",
"limit": 1
}
}
```
### Get Character
| | |
|---|---|
| **Endpoint** | `GET /api/v1/characters/<id>` |
| **Description** | Get full character details including inventory, equipment, and skills |
| **Auth Required** | Yes |
**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_456",
"name": "Thorin Ironheart",
"player_class": {
"class_id": "vanguard",
"name": "Vanguard",
"description": "A seasoned warrior...",
"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 tanking specialization",
"nodes": []
}
],
"starting_equipment": ["rusty_sword"],
"starting_abilities": ["basic_attack"]
},
"origin": {
"id": "soul_revenant",
"name": "Soul Revenant",
"description": "Returned from death...",
"starting_location": {
"id": "forgotten_crypt",
"name": "The Forgotten Crypt",
"region": "The Deadlands",
"description": "An ancient burial site..."
},
"narrative_hooks": [],
"starting_bonus": {}
},
"level": 5,
"experience": 250,
"base_stats": {
"strength": 14,
"dexterity": 10,
"constitution": 14,
"intelligence": 8,
"wisdom": 10,
"charisma": 9
},
"unlocked_skills": ["shield_bash", "iron_defense"],
"inventory": [],
"equipped": {},
"gold": 1000,
"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-15T12:00:00Z",
"result": null,
"error": {
"code": "NOT_FOUND",
"message": "Character not found: char_999",
"details": {}
}
}
```
### Create Character
| | |
|---|---|
| **Endpoint** | `POST /api/v1/characters` |
| **Description** | Create new character (validates tier limits) |
| **Auth Required** | Yes |
**Request Body:**
```json
{
"name": "Thorin Ironheart",
"class_id": "vanguard",
"origin_id": "soul_revenant"
}
```
**Validation Rules:**
- **name**: 2-50 characters, letters/numbers/spaces/hyphens/apostrophes only
- **class_id**: Must be one of: vanguard, assassin, arcanist, luminary, wildstrider, oathkeeper, necromancer, lorekeeper
- **origin_id**: Must be one of: soul_revenant, memory_thief, shadow_apprentice, escaped_captive
**Response (201 Created):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 201,
"timestamp": "2025-11-15T12:00:00Z",
"result": {
"character_id": "char_123",
"name": "Thorin Ironheart",
"class": "vanguard",
"class_name": "Vanguard",
"origin": "soul_revenant",
"origin_name": "Soul Revenant",
"level": 1,
"gold": 0,
"current_location": "forgotten_crypt",
"message": "Character created successfully"
}
}
```
**Error Response (400 Bad Request - Limit Exceeded):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 400,
"timestamp": "2025-11-15T12:00:00Z",
"result": null,
"error": {
"code": "CHARACTER_LIMIT_EXCEEDED",
"message": "Character limit reached for free tier (1/1). Upgrade your subscription to create more characters.",
"details": {}
}
}
```
### Delete Character
| | |
|---|---|
| **Endpoint** | `DELETE /api/v1/characters/<id>` |
| **Description** | Permanently delete character and all associated game sessions |
| **Auth Required** | Yes |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-15T12:00:00Z",
"result": {
"message": "Character deleted successfully",
"character_id": "char_123"
}
}
```
### Unlock Skill
| | |
|---|---|
| **Endpoint** | `POST /api/v1/characters/<id>/skills/unlock` |
| **Description** | Unlock skill node (validates prerequisites and skill points) |
| **Auth Required** | Yes |
**Request Body:**
```json
{
"skill_id": "shield_bash"
}
```
**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_bash",
"unlocked_skills": ["shield_bash"],
"available_points": 0
}
}
```
### Respec Skills
| | |
|---|---|
| **Endpoint** | `POST /api/v1/characters/<id>/skills/respec` |
| **Description** | Reset all unlocked skills (costs level × 100 gold) |
| **Auth Required** | Yes |
**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": 500,
"available_points": 5
}
}
```
---
## Classes & Origins (Reference Data)
### List Classes
| | |
|---|---|
| **Endpoint** | `GET /api/v1/classes` |
| **Description** | Get all available player classes |
| **Auth Required** | No |
**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": "A seasoned warrior who stands at the front lines...",
"base_stats": {
"strength": 14,
"dexterity": 10,
"constitution": 14,
"intelligence": 8,
"wisdom": 10,
"charisma": 9
},
"skill_trees": ["Shield Bearer", "Weapon Master"],
"starting_equipment": ["rusty_sword"],
"starting_abilities": ["basic_attack"]
}
],
"count": 8
}
}
```
### Get Class
| | |
|---|---|
| **Endpoint** | `GET /api/v1/classes/<class_id>` |
| **Description** | Get full class details with skill trees |
| **Auth Required** | No |
**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": "A seasoned warrior who stands at the front lines...",
"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 tanking specialization",
"nodes": [
{
"skill_id": "shield_bash",
"name": "Shield Bash",
"description": "Strike with shield for 120% damage and 1-turn stun",
"tier": 1,
"prerequisites": [],
"effects": {
"damage_multiplier": 1.2
},
"unlocks_abilities": ["shield_bash"]
}
]
}
],
"starting_equipment": ["rusty_sword"],
"starting_abilities": ["basic_attack"]
}
}
```
### List Origins
| | |
|---|---|
| **Endpoint** | `GET /api/v1/origins` |
| **Description** | Get all available character origins |
| **Auth Required** | No |
**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": "Soul Revenant",
"description": "Centuries ago, you perished in battle...",
"starting_location": {
"id": "forgotten_crypt",
"name": "The Forgotten Crypt",
"region": "The Deadlands",
"description": "An ancient burial site shrouded in mist..."
},
"narrative_hooks": [
"Why were you brought back to life?",
"What happened in the centuries you were dead?"
],
"starting_bonus": {
"trait": "Deathless Resolve",
"description": "Having already died once, death holds no fear for you",
"effect": "Once per day, when reduced to 0 HP, survive with 1 HP instead"
}
}
],
"count": 4
}
}
```
---
## Inventory
### Get Inventory
| | |
|---|---|
| **Endpoint** | `GET /api/v1/characters/<character_id>/inventory` |
| **Description** | Get character inventory and equipped items |
| **Auth Required** | Yes |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-27T12:00:00Z",
"result": {
"inventory": [
{
"item_id": "gen_abc123",
"name": "Flaming Dagger",
"item_type": "weapon",
"rarity": "rare",
"value": 250,
"description": "A dagger imbued with fire magic"
}
],
"equipped": {
"weapon": {
"item_id": "rusty_sword",
"name": "Rusty Sword",
"item_type": "weapon",
"rarity": "common"
},
"helmet": null,
"chest": null,
"legs": null,
"boots": null,
"gloves": null,
"ring1": null,
"ring2": null,
"amulet": null
},
"inventory_count": 5,
"max_inventory": 100
}
}
```
### Equip Item
| | |
|---|---|
| **Endpoint** | `POST /api/v1/characters/<character_id>/inventory/equip` |
| **Description** | Equip an item from inventory to a specified slot |
| **Auth Required** | Yes |
**Request Body:**
```json
{
"item_id": "gen_abc123",
"slot": "weapon"
}
```
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-27T12:00:00Z",
"result": {
"message": "Equipped Flaming Dagger to weapon slot",
"equipped": {
"weapon": {...},
"helmet": null
},
"unequipped_item": {
"item_id": "rusty_sword",
"name": "Rusty Sword"
}
}
}
```
### Unequip Item
| | |
|---|---|
| **Endpoint** | `POST /api/v1/characters/<character_id>/inventory/unequip` |
| **Description** | Unequip an item from a specified slot (returns to inventory) |
| **Auth Required** | Yes |
**Request Body:**
```json
{
"slot": "weapon"
}
```
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-27T12:00:00Z",
"result": {
"message": "Unequipped Flaming Dagger from weapon slot",
"unequipped_item": {...},
"equipped": {...}
}
}
```
### Use Item
| | |
|---|---|
| **Endpoint** | `POST /api/v1/characters/<character_id>/inventory/use` |
| **Description** | Use a consumable item from inventory |
| **Auth Required** | Yes |
**Request Body:**
```json
{
"item_id": "health_potion_small"
}
```
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-27T12:00:00Z",
"result": {
"item_used": "Small Health Potion",
"effects_applied": [
{
"effect_name": "Healing",
"effect_type": "hot",
"value": 25,
"message": "Restored 25 HP"
}
],
"hp_restored": 25,
"mp_restored": 0,
"message": "Used Small Health Potion: Restored 25 HP"
}
}
```
### Drop Item
| | |
|---|---|
| **Endpoint** | `DELETE /api/v1/characters/<character_id>/inventory/<item_id>` |
| **Description** | Drop (remove) an item from inventory |
| **Auth Required** | Yes |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-27T12:00:00Z",
"result": {
"message": "Dropped Rusty Sword",
"dropped_item": {...},
"inventory_count": 4
}
}
```
---
## Health
### Health Check
| | |
|---|---|
| **Endpoint** | `GET /api/v1/health` |
| **Description** | Check API service status and version |
| **Auth Required** | No |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-16T10:30:00Z",
"result": {
"status": "ok",
"service": "Code of Conquest API",
"version": "0.1.0"
},
"error": null,
"meta": {}
}
```
---
## Sessions
### List Sessions
| | |
|---|---|
| **Endpoint** | `GET /api/v1/sessions` |
| **Description** | Get all active sessions for current user |
| **Auth Required** | Yes |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-16T10:30:00Z",
"result": [
{
"session_id": "sess_789",
"character_id": "char_456",
"character_name": "Thorin",
"turn_number": 5,
"status": "active",
"created_at": "2025-11-16T10:00:00Z",
"last_activity": "2025-11-16T10:25:00Z",
"in_combat": false,
"game_state": {
"current_location": "crossville_village",
"location_type": "town",
"in_combat": false,
"combat_round": null
}
}
]
}
```
### Create Session
| | |
|---|---|
| **Endpoint** | `POST /api/v1/sessions` |
| **Description** | Create new solo game session |
| **Auth Required** | Yes |
**Request Body:**
```json
{
"character_id": "char_456"
}
```
**Response (201 Created):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 201,
"timestamp": "2025-11-16T10:30:00Z",
"result": {
"session_id": "sess_789",
"character_id": "char_456",
"turn_number": 0,
"game_state": {
"current_location": "Crossroads Village",
"location_type": "town",
"active_quests": []
}
}
}
```
**Session Limits by Tier:**
| Tier | Max Active Sessions |
|------|---------------------|
| FREE | 1 |
| BASIC | 2 |
| PREMIUM | 3 |
| ELITE | 5 |
### Get Session State
| | |
|---|---|
| **Endpoint** | `GET /api/v1/sessions/<session_id>` |
| **Description** | Get current session state with available actions |
| **Auth Required** | Yes |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-16T10:30:00Z",
"result": {
"session_id": "sess_789",
"character_id": "char_456",
"turn_number": 5,
"status": "active",
"in_combat": false,
"game_state": {
"current_location": "The Rusty Anchor",
"location_type": "tavern",
"active_quests": ["quest_goblin_cave"],
"in_combat": false
},
"available_actions": [
{
"prompt_id": "ask_locals",
"display_text": "Ask locals for information",
"description": "Talk to NPCs to learn about quests and rumors",
"category": "ask_question"
},
{
"prompt_id": "rest",
"display_text": "Rest and recover",
"description": "Take a short rest to recover health",
"category": "rest"
}
]
}
}
```
### Take Action
| | |
|---|---|
| **Endpoint** | `POST /api/v1/sessions/<session_id>/action` |
| **Description** | Submit action for AI processing (async) |
| **Auth Required** | Yes |
**Request Body:**
```json
{
"action_type": "button",
"prompt_id": "ask_locals"
}
```
**Response (202 Accepted):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 202,
"timestamp": "2025-11-16T10:30:00Z",
"result": {
"job_id": "abc-123",
"status": "queued",
"message": "Your action is being processed..."
}
}
```
**Notes:**
- Only button actions with predefined prompts are supported
- Poll `/api/v1/jobs/<job_id>/status` to check processing status
- Rate limits apply based on subscription tier
### Get Job Status
| | |
|---|---|
| **Endpoint** | `GET /api/v1/jobs/<job_id>/status` |
| **Description** | Get status of an async AI processing job |
| **Auth Required** | Yes |
**Response (200 OK - Processing):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-16T10:30:05Z",
"result": {
"job_id": "ai_TaskType.NARRATIVE_abc123",
"status": "processing"
}
}
```
**Response (200 OK - Completed):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-16T10:30:10Z",
"result": {
"job_id": "ai_TaskType.NARRATIVE_abc123",
"status": "completed",
"dm_response": "As you search for supplies in the village, you notice...",
"tokens_used": 273,
"model": "meta/meta-llama-3-8b-instruct"
}
}
```
### Get Conversation History
| | |
|---|---|
| **Endpoint** | `GET /api/v1/sessions/<session_id>/history` |
| **Description** | Get paginated conversation history |
| **Auth Required** | Yes |
**Query Parameters:**
- `limit` (int, default 20, max 100) - Number of entries to return
- `offset` (int, default 0) - Number of entries to skip
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-16T10:30:00Z",
"result": {
"total_turns": 5,
"history": [
{
"turn": 1,
"action": "I explore the tavern",
"dm_response": "You enter a smoky tavern filled with weary travelers...",
"timestamp": "2025-11-16T10:30:00Z"
}
],
"pagination": {
"limit": 20,
"offset": 0,
"has_more": false
}
}
}
```
### Delete Session
| | |
|---|---|
| **Endpoint** | `DELETE /api/v1/sessions/<session_id>` |
| **Description** | Permanently delete a session and all associated chat messages |
| **Auth Required** | Yes |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-16T10:30:00Z",
"result": {
"message": "Session deleted successfully",
"session_id": "sess_789"
}
}
```
### Get Usage Information
| | |
|---|---|
| **Endpoint** | `GET /api/v1/usage` |
| **Description** | Get user's daily usage information (turn limits) |
| **Auth Required** | Yes |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-27T12:00:00Z",
"result": {
"user_id": "user_123",
"user_tier": "free",
"current_usage": 15,
"daily_limit": 50,
"remaining": 35,
"reset_time": "2025-11-27T00:00:00+00:00",
"is_limited": false,
"is_unlimited": false
}
}
```
---
## Travel
### Get Available Destinations
| | |
|---|---|
| **Endpoint** | `GET /api/v1/travel/available` |
| **Description** | Get all locations the player can travel to |
| **Auth Required** | Yes |
**Query Parameters:**
- `session_id` (required) - Active session ID
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-25T10:30:00Z",
"result": {
"current_location": "crossville_village",
"destinations": [
{
"location_id": "crossville_tavern",
"name": "The Rusty Anchor Tavern",
"location_type": "tavern",
"region_id": "crossville",
"description": "A cozy tavern where travelers share tales..."
}
]
}
}
```
### Travel to Location
| | |
|---|---|
| **Endpoint** | `POST /api/v1/travel` |
| **Description** | Travel to a new location (must be discovered) |
| **Auth Required** | Yes |
**Request Body:**
```json
{
"session_id": "sess_789",
"location_id": "crossville_tavern"
}
```
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-25T10:30:00Z",
"result": {
"location": {
"location_id": "crossville_tavern",
"name": "The Rusty Anchor Tavern",
"location_type": "tavern",
"region_id": "crossville",
"description": "A cozy tavern where travelers share tales...",
"lore": "Founded decades ago by a retired adventurer...",
"ambient_description": "The scent of ale and roasting meat fills the air...",
"available_quests": ["quest_missing_trader"],
"npc_ids": ["npc_grom_ironbeard"],
"discoverable_locations": ["crossville_forest"],
"is_starting_location": false,
"tags": ["tavern", "social", "merchant", "safe"]
},
"npcs_present": [
{
"npc_id": "npc_grom_ironbeard",
"name": "Grom Ironbeard",
"role": "bartender",
"appearance": "Stout dwarf with a braided grey beard"
}
],
"game_state": {
"current_location": "crossville_tavern",
"location_type": "tavern",
"active_quests": []
}
}
}
```
### Get Location Details
| | |
|---|---|
| **Endpoint** | `GET /api/v1/travel/location/<location_id>` |
| **Description** | Get full details for a specific location |
| **Auth Required** | Yes |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-25T10:30:00Z",
"result": {
"location": {...},
"npcs_present": [...]
}
}
```
### Get Current Location
| | |
|---|---|
| **Endpoint** | `GET /api/v1/travel/current` |
| **Description** | Get details about the current location in a session |
| **Auth Required** | Yes |
**Query Parameters:**
- `session_id` (required) - Active session ID
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-25T10:30:00Z",
"result": {
"location": {...},
"npcs_present": [...]
}
}
```
---
## NPCs
### Get NPC Details
| | |
|---|---|
| **Endpoint** | `GET /api/v1/npcs/<npc_id>` |
| **Description** | Get NPC details with knowledge filtered by relationship |
| **Auth Required** | Yes |
**Query Parameters:**
- `character_id` (optional) - Filter knowledge by character's relationship
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-25T10:30:00Z",
"result": {
"npc_id": "npc_grom_ironbeard",
"name": "Grom Ironbeard",
"role": "bartender",
"location_id": "crossville_tavern",
"image_url": "/static/images/npcs/crossville/grom_ironbeard.png",
"personality": {
"traits": ["gruff", "observant", "secretly kind"],
"speech_style": "Uses dwarven expressions, speaks in short sentences",
"quirks": ["Polishes same mug when thinking", "Snorts when amused"]
},
"appearance": {
"brief": "Stout dwarf with a braided grey beard",
"detailed": "A weathered dwarf with deep-set eyes..."
},
"available_knowledge": [
"The mayor has been acting strange lately",
"Strange lights seen in the forest"
],
"interaction_summary": {
"interaction_count": 3,
"relationship_level": 65,
"first_met": "2025-11-20T10:30:00Z"
},
"tags": ["merchant", "quest_giver", "information"]
}
}
```
### Talk to NPC
| | |
|---|---|
| **Endpoint** | `POST /api/v1/npcs/<npc_id>/talk` |
| **Description** | Start or continue conversation with NPC (generates AI dialogue) |
| **Auth Required** | Yes |
**Request Body (Initial Greeting):**
```json
{
"session_id": "sess_789",
"topic": "greeting"
}
```
**Request Body (Player Response - Bidirectional Dialogue):**
```json
{
"session_id": "sess_789",
"player_response": "What can you tell me about the bandits?"
}
```
**Response (202 Accepted):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 202,
"timestamp": "2025-11-25T10:30:00Z",
"result": {
"job_id": "ai_npc_dialogue_xyz789",
"status": "queued",
"message": "Starting conversation with Grom Ironbeard...",
"npc_name": "Grom Ironbeard",
"npc_role": "bartender"
}
}
```
**Job Result (when completed):**
```json
{
"job_id": "ai_npc_dialogue_xyz789",
"status": "completed",
"result": {
"context_type": "npc_dialogue",
"dialogue": "*polishes mug thoughtfully* \"Ah, another adventurer. What'll it be?\"",
"tokens_used": 728,
"npc_name": "Grom Ironbeard",
"npc_id": "npc_grom_ironbeard",
"character_name": "Thorin",
"player_line": "greeting",
"conversation_history": [
{
"player_line": "Hello there!",
"npc_response": "*nods gruffly* \"Welcome to the Rusty Anchor.\""
}
]
}
}
```
### Get NPCs at Location
| | |
|---|---|
| **Endpoint** | `GET /api/v1/npcs/at-location/<location_id>` |
| **Description** | Get all NPCs present at a location |
| **Auth Required** | Yes |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-25T10:30:00Z",
"result": {
"location_id": "crossville_tavern",
"npcs": [
{
"npc_id": "npc_grom_ironbeard",
"name": "Grom Ironbeard",
"role": "bartender",
"appearance": "Stout dwarf with a braided grey beard",
"tags": ["merchant", "quest_giver"],
"image_url": "/static/images/npcs/crossville/grom_ironbeard.png"
}
]
}
}
```
### Adjust NPC Relationship
| | |
|---|---|
| **Endpoint** | `POST /api/v1/npcs/<npc_id>/relationship` |
| **Description** | Adjust relationship level with NPC |
| **Auth Required** | Yes |
**Request Body:**
```json
{
"character_id": "char_123",
"adjustment": 10
}
```
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-25T10:30:00Z",
"result": {
"npc_id": "npc_grom_ironbeard",
"relationship_level": 75
}
}
```
### Set NPC Custom Flag
| | |
|---|---|
| **Endpoint** | `POST /api/v1/npcs/<npc_id>/flag` |
| **Description** | Set custom flag on NPC interaction (for conditional secrets) |
| **Auth Required** | Yes |
**Request Body:**
```json
{
"character_id": "char_123",
"flag_name": "helped_with_rats",
"flag_value": true
}
```
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-25T10:30:00Z",
"result": {
"npc_id": "npc_grom_ironbeard",
"flag_name": "helped_with_rats",
"flag_value": true
}
}
```
---
## Chat / Conversation History
The Chat API provides access to complete player-NPC conversation history. All dialogue exchanges are stored in the `chat_messages` collection for unlimited history.
### Get All Conversations Summary
| | |
|---|---|
| **Endpoint** | `GET /api/v1/characters/<character_id>/chats` |
| **Description** | Get summary of all NPC conversations for a character |
| **Auth Required** | Yes |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-25T14:30:00Z",
"result": {
"conversations": [
{
"npc_id": "npc_grom_ironbeard",
"npc_name": "Grom Ironbeard",
"last_message_timestamp": "2025-11-25T14:30:00Z",
"message_count": 15,
"recent_preview": "Aye, the rats in the cellar have been causing trouble..."
}
]
}
}
```
### Get Conversation with Specific NPC
| | |
|---|---|
| **Endpoint** | `GET /api/v1/characters/<character_id>/chats/<npc_id>` |
| **Description** | Get paginated conversation history with a specific NPC |
| **Auth Required** | Yes |
**Query Parameters:**
- `limit` (optional): Maximum messages to return (default: 50, max: 100)
- `offset` (optional): Number of messages to skip (default: 0)
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-25T14:30:00Z",
"result": {
"npc_id": "npc_grom_ironbeard",
"npc_name": "Grom Ironbeard",
"total_messages": 15,
"messages": [
{
"message_id": "msg_abc123",
"character_id": "char_123",
"npc_id": "npc_grom_ironbeard",
"player_message": "What rumors have you heard?",
"npc_response": "*leans in* Strange folk been coming through lately...",
"timestamp": "2025-11-25T14:30:00Z",
"context": "dialogue",
"location_id": "crossville_tavern",
"session_id": "sess_789",
"metadata": {},
"is_deleted": false
}
],
"pagination": {
"limit": 50,
"offset": 0,
"has_more": false
}
}
}
```
### Search Messages
| | |
|---|---|
| **Endpoint** | `GET /api/v1/characters/<character_id>/chats/search` |
| **Description** | Search messages by text with optional filters |
| **Auth Required** | Yes |
**Query Parameters:**
- `q` (required): Search text to find in player_message and npc_response
- `npc_id` (optional): Filter by specific NPC
- `context` (optional): Filter by message context type
- `date_from` (optional): Start date in ISO format
- `date_to` (optional): End date in ISO format
- `limit` (optional): Maximum messages to return (default: 50, max: 100)
- `offset` (optional): Number of messages to skip (default: 0)
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-25T14:30:00Z",
"result": {
"search_text": "quest",
"filters": {
"npc_id": "npc_grom_ironbeard",
"context": "quest_offered",
"date_from": null,
"date_to": null
},
"total_results": 2,
"messages": [...],
"pagination": {
"limit": 50,
"offset": 0,
"has_more": false
}
}
}
```
### Delete Message
| | |
|---|---|
| **Endpoint** | `DELETE /api/v1/characters/<character_id>/chats/<message_id>` |
| **Description** | Soft delete a message (privacy/moderation) |
| **Auth Required** | Yes |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-25T14:30:00Z",
"result": {
"message_id": "msg_abc123",
"deleted": true
}
}
```
---
## Combat
### Start Combat
| | |
|---|---|
| **Endpoint** | `POST /api/v1/combat/start` |
| **Description** | Start a new combat encounter |
| **Auth Required** | Yes |
**Request Body:**
```json
{
"session_id": "sess_123",
"enemy_ids": ["goblin", "goblin", "goblin_shaman"]
}
```
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-27T12:00:00Z",
"result": {
"encounter_id": "enc_abc123",
"combatants": [
{
"combatant_id": "char_456",
"name": "Thorin",
"is_player": true,
"current_hp": 100,
"max_hp": 100,
"current_mp": 50,
"max_mp": 50,
"initiative": 15,
"abilities": ["basic_attack", "shield_bash"]
}
],
"turn_order": ["char_456", "goblin_0", "goblin_shaman_0", "goblin_1"],
"current_turn": "char_456",
"round_number": 1,
"status": "active"
}
}
```
### Get Combat State
| | |
|---|---|
| **Endpoint** | `GET /api/v1/combat/<session_id>/state` |
| **Description** | Get current combat state for a session |
| **Auth Required** | Yes |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-27T12:00:00Z",
"result": {
"in_combat": true,
"encounter": {
"encounter_id": "enc_abc123",
"combatants": [...],
"turn_order": [...],
"current_turn": "char_456",
"round_number": 2,
"status": "active",
"combat_log": [
"Thorin attacks Goblin for 15 damage!",
"Goblin attacks Thorin for 5 damage!"
]
}
}
}
```
### Execute Combat Action
| | |
|---|---|
| **Endpoint** | `POST /api/v1/combat/<session_id>/action` |
| **Description** | Execute a combat action for a combatant |
| **Auth Required** | Yes |
**Request Body:**
```json
{
"combatant_id": "char_456",
"action_type": "attack",
"target_ids": ["goblin_0"],
"ability_id": "shield_bash"
}
```
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-27T12:00:00Z",
"result": {
"success": true,
"message": "Shield Bash hits Goblin for 18 damage and stuns!",
"damage_results": [
{
"target_id": "goblin_0",
"damage": 18,
"is_critical": false
}
],
"effects_applied": [
{
"target_id": "goblin_0",
"effect": "stunned",
"duration": 1
}
],
"combat_ended": false,
"combat_status": null,
"next_combatant_id": "goblin_1"
}
}
```
### Execute Enemy Turn
| | |
|---|---|
| **Endpoint** | `POST /api/v1/combat/<session_id>/enemy-turn` |
| **Description** | Execute the current enemy's turn using AI logic |
| **Auth Required** | Yes |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-27T12:00:00Z",
"result": {
"success": true,
"message": "Goblin attacks Thorin for 8 damage!",
"damage_results": [...],
"effects_applied": [],
"combat_ended": false,
"combat_status": null,
"next_combatant_id": "char_456"
}
}
```
### Attempt Flee
| | |
|---|---|
| **Endpoint** | `POST /api/v1/combat/<session_id>/flee` |
| **Description** | Attempt to flee from combat |
| **Auth Required** | Yes |
**Request Body:**
```json
{
"combatant_id": "char_456"
}
```
**Response (200 OK - Success):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-27T12:00:00Z",
"result": {
"success": true,
"message": "Successfully fled from combat!",
"combat_ended": true,
"combat_status": "fled"
}
}
```
### End Combat
| | |
|---|---|
| **Endpoint** | `POST /api/v1/combat/<session_id>/end` |
| **Description** | Force end the current combat (debug/admin endpoint) |
| **Auth Required** | Yes |
**Request Body:**
```json
{
"outcome": "victory"
}
```
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-27T12:00:00Z",
"result": {
"outcome": "victory",
"rewards": {
"experience": 100,
"gold": 50,
"items": [...],
"level_ups": []
}
}
}
```
### List Enemies
| | |
|---|---|
| **Endpoint** | `GET /api/v1/combat/enemies` |
| **Description** | List all available enemy templates |
| **Auth Required** | No |
**Query Parameters:**
- `difficulty` (optional): Filter by difficulty (easy, medium, hard, boss)
- `tag` (optional): Filter by tag (undead, beast, humanoid, etc.)
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-27T12:00:00Z",
"result": {
"enemies": [
{
"enemy_id": "goblin",
"name": "Goblin Scout",
"description": "A small, cunning creature...",
"difficulty": "easy",
"tags": ["humanoid", "goblinoid"],
"experience_reward": 15,
"gold_reward_range": [5, 15]
}
]
}
}
```
### Get Enemy Details
| | |
|---|---|
| **Endpoint** | `GET /api/v1/combat/enemies/<enemy_id>` |
| **Description** | Get detailed information about a specific enemy template |
| **Auth Required** | No |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-27T12:00:00Z",
"result": {
"enemy_id": "goblin",
"name": "Goblin Scout",
"description": "A small, cunning creature with sharp claws",
"base_stats": {
"strength": 8,
"dexterity": 14,
"constitution": 10
},
"abilities": ["quick_strike", "dodge"],
"loot_table": [...],
"difficulty": "easy",
"experience_reward": 15,
"gold_reward_min": 5,
"gold_reward_max": 15
}
}
```
### Debug: Reset HP/MP
| | |
|---|---|
| **Endpoint** | `POST /api/v1/combat/<session_id>/debug/reset-hp-mp` |
| **Description** | Reset player combatant's HP and MP to full (debug endpoint) |
| **Auth Required** | Yes |
**Response (200 OK):**
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 200,
"timestamp": "2025-11-27T12:00:00Z",
"result": {
"success": true,
"message": "HP and MP reset to full",
"current_hp": 100,
"max_hp": 100,
"current_mp": 50,
"max_mp": 50
}
}
```
---
## Game Mechanics
### Perform Skill Check or Search
| | |
|---|---|
| **Endpoint** | `POST /api/v1/game/check` |
| **Description** | Perform a skill check or search action and get deterministic dice roll results |
| **Auth Required** | Yes |
**Request Body (Skill Check):**
```json
{
"character_id": "char_123",
"check_type": "skill",
"skill": "persuasion",
"dc": 15,
"bonus": 2,
"context": {
"npc_name": "Guard Captain"
}
}
```
**Request Body (Search Action):**
```json
{
"character_id": "char_123",
"check_type": "search",
"location_type": "forest",
"dc": 12,
"bonus": 0
}
```
**Request Body (Using Difficulty Name):**
```json
{
"character_id": "char_123",
"check_type": "skill",
"skill": "stealth",
"difficulty": "hard",
"bonus": 1
}
```
**Response (200 OK - Skill Check Success):**
```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"
}
}
}
```
**Response (200 OK - Search Success):**
```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": 12,
"success": true,
"margin": 8,
"skill_type": "perception"
},
"items_found": [
{
"template_key": "ancient_coin",
"name": "Ancient Coin",
"description": "A weathered coin from ages past",
"value": 25
}
],
"gold_found": 15
}
}
```
**Notes:**
- `check_type` must be "search" or "skill"
- For skill checks, `skill` is required
- `dc` or `difficulty` must be provided (dc takes precedence)
- Valid difficulty values: trivial (5), easy (10), medium (15), hard (20), very_hard (25), nearly_impossible (30)
### List Available Skills
| | |
|---|---|
| **Endpoint** | `GET /api/v1/game/skills` |
| **Description** | Get all available skill types with their associated stats |
| **Auth Required** | No |
**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": "insight", "stat": "wisdom"},
{"name": "stealth", "stat": "dexterity"},
{"name": "persuasion", "stat": "charisma"},
{"name": "athletics", "stat": "strength"}
]
}
}
```
### List Difficulty Levels
| | |
|---|---|
| **Endpoint** | `GET /api/v1/game/difficulties` |
| **Description** | Get all difficulty levels and their DC values |
| **Auth Required** | No |
**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}
]
}
}
```
---
## Error Responses
### Standard Error Format
```json
{
"app": "Code of Conquest",
"version": "0.1.0",
"status": 400,
"timestamp": "2025-11-14T12:00:00Z",
"result": null,
"error": {
"code": "INVALID_ACTION",
"message": "Not your turn",
"details": {
"current_turn": "char456",
"your_character": "char123"
}
}
}
```
### Common Error Codes
| Code | Status | Description |
|------|--------|-------------|
| `UNAUTHORIZED` | 401 | Invalid or missing auth token |
| `FORBIDDEN` | 403 | Insufficient permissions |
| `NOT_FOUND` | 404 | Resource not found |
| `INVALID_INPUT` | 400 | Validation error |
| `RATE_LIMIT_EXCEEDED` | 429 | Too many requests |
| `CHARACTER_LIMIT_EXCEEDED` | 400 | User has reached character limit for their tier |
| `SESSION_LIMIT_EXCEEDED` | 409 | User has reached session limit for their tier |
| `CHARACTER_NOT_FOUND` | 404 | Character does not exist or not accessible |
| `SKILL_UNLOCK_ERROR` | 400 | Skill unlock failed (prerequisites, points, or tier) |
| `INSUFFICIENT_GOLD` | 400 | Not enough gold |
| `INSUFFICIENT_RESOURCES` | 400 | Not enough MP/items for action |
| `INVALID_ACTION` | 400 | Action not allowed |
| `SESSION_FULL` | 400 | Session at max capacity |
| `NOT_YOUR_TURN` | 400 | Not active player's turn |
| `AI_LIMIT_EXCEEDED` | 429 | Daily AI call limit reached |
| `PREMIUM_REQUIRED` | 403 | Feature requires premium subscription |
| `ALREADY_IN_COMBAT` | 400 | Session is already in combat |
| `NOT_IN_COMBAT` | 404 | Session is not in combat |
| `INVENTORY_FULL` | 400 | Inventory is full |
| `CANNOT_EQUIP` | 400 | Item cannot be equipped |
| `CANNOT_USE_ITEM` | 400 | Item cannot be used |
---
## Rate Limiting
| Tier | Requests/Minute | AI Calls/Day | Max Sessions |
|------|-----------------|--------------|--------------|
| FREE | 30 | 50 | 1 |
| BASIC | 60 | 200 | 2 |
| PREMIUM | 120 | 1000 | 3 |
| ELITE | 300 | Unlimited | 5 |
**Rate Limit Headers:**
```
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1699999999
```
---
## Pagination
Endpoints that return lists support pagination:
**Query Parameters:**
- `page` - Page number (default: 1)
- `limit` - Items per page (default: 20, max: 100)
**Response Meta:**
```json
{
"meta": {
"page": 1,
"limit": 20,
"total": 100,
"pages": 5
}
}
```