2214 lines
46 KiB
Markdown
2214 lines
46 KiB
Markdown
# 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
|
||
}
|
||
}
|
||
```
|