Skip to content

Characters Service

Manage characters within a campaign, including their statistics, assets, notes, inventory, and supernatural abilities.

Usage

from vclient import characters_service

characters = characters_service(
    on_behalf_of="USER_ID",
    company_id="COMPANY_ID"
)

The on_behalf_of user ID is required and is sent on every request, including reads. The acting user's role determines what is visible.

Access control

Visibility of STORYTELLER characters depends on the acting user's role:

  • PLAYER and NPC characters are visible to every approved company member.
  • STORYTELLER characters are visible only to STORYTELLER and ADMIN roles. For a PLAYER:
  • List results omit STORYTELLER characters (filtering with character_type="STORYTELLER" returns an empty page).
  • Fetching a STORYTELLER character by ID, or any of its sub-resources (traits, inventory, notes, assets, statistics), raises AuthorizationError (403).
  • Only STORYTELLER and ADMIN roles may create() a character with type="STORYTELLER" or update() an existing character's type to STORYTELLER. A PLAYER attempting either raises AuthorizationError (403).

NPC management

NPC management is gated by the company's settings.permission_manage_npc setting (ManageNPCPermission):

  • UNRESTRICTED (default): any approved company member may manage NPC characters.
  • STORYTELLER: only STORYTELLER and ADMIN roles may manage NPC characters. A PLAYER attempting any of the following raises AuthorizationError (403):
  • Creating an NPC character, or converting an existing character to type="NPC".
  • Updating or deleting an NPC character.
  • Adding, updating, or deleting an NPC character's traits or inventory items.
  • Uploading or deleting an NPC character's images.

Viewing an NPC character and rolling dice for an NPC are never affected by this setting; any approved member may always access those endpoints.

Player and creator assignment

The user_player_id and user_creator_id fields on Character are both nullable, and their values are constrained by character type:

  • PLAYER characters always have a non-null user_player_id. NPC and STORYTELLER characters always have user_player_id = null.
  • user_creator_id may be null if the creating user was deleted.

Assignment rules are enforced server-side and surface as ValidationError (400):

  • Creating a PLAYER character without a user_player_id defaults it to the acting user.
  • Creating an NPC or STORYTELLER character with a non-null user_player_id raises ValidationError (400).
  • Assigning a user_player_id to an existing NPC or STORYTELLER character raises ValidationError (400).
  • Converting a PLAYER character to NPC or STORYTELLER automatically clears user_player_id to null. No explicit user_player_id=None is required in the request.
  • Converting an NPC or STORYTELLER character to PLAYER requires a user_player_id in the same update() call; omitting it raises ValidationError (400).

Methods

CRUD Operations

Method Returns Description
get(character_id) Character Get a character by ID
create(CharacterCreate, **kwargs) Character Create a new character
update(character_id, CharacterUpdate, **kwargs) Character Update a character
delete(character_id) None Delete a character

Pagination

Method Returns Description
get_page(limit?, offset?, campaign_id?, user_player_id?, character_class?, character_type?, status?, is_temporary?) PaginatedResponse[Character] Get a page of characters with optional filters
list_all(...) list[Character] Get all characters (supports same filters)
iter_all(limit?, ...) AsyncIterator[Character] Iterate through all characters

Statistics

Method Returns Description
get_statistics(character_id, num_top_traits?) RollStatistics Get dice roll statistics

Roll Analytics

Statistics include success rates, critical frequencies, and most-used traits. Use this data to understand how a character performs in gameplay.

Full Sheet

Method Returns Description
get_full_sheet(character_id, include_available_traits?) CharacterFullSheet Get hierarchical character sheet with all traits
get_full_sheet_category(character_id, category_id, include_available_traits?) FullSheetTraitCategory Get a single category slice of the full sheet

Sheet Structure

The full sheet returns all traits organized as sections > categories > subcategories > character traits. The skeleton includes all structures for the character's class and game version, even if empty. Use this to render a complete character sheet UI.

Available Traits

Set include_available_traits=True to populate the available_traits field on each category and subcategory with standard traits the character could add. When not set, these lists are always empty. Custom traits are excluded.

Assets

Method Returns Description
get_assets_page(character_id, limit?, offset?) PaginatedResponse[Asset] Get a page of assets
list_all_assets(character_id) list[Asset] Get all assets
iter_all_assets(character_id, limit?) AsyncIterator[Asset] Iterate through assets
get_asset(character_id, asset_id) Asset Get an asset
upload_asset(character_id, filename, content) Asset Upload an asset
delete_asset(character_id, asset_id) None Delete an asset

Notes

Method Returns Description
get_notes_page(character_id, limit?, offset?) PaginatedResponse[Note] Get a page of notes
list_all_notes(character_id) list[Note] Get all notes
iter_all_notes(character_id, limit?) AsyncIterator[Note] Iterate through notes
get_note(character_id, note_id) Note Get a note
create_note(character_id, NoteCreate, **kwargs) Note Create a note
update_note(character_id, note_id, NoteUpdate, **kwargs) Note Update a note
delete_note(character_id, note_id) None Delete a note

Inventory

Method Returns Description
get_inventory_page(character_id, limit?, offset?) PaginatedResponse[InventoryItem] Get a page of inventory items
list_all_inventory(character_id) list[InventoryItem] Get all inventory items
iter_all_inventory(character_id, limit?) AsyncIterator[InventoryItem] Iterate through items
get_inventory_item(character_id, item_id) InventoryItem Get an item
create_inventory_item(character_id, InventoryItemCreate, **kwargs) InventoryItem Create an item
update_inventory_item(character_id, item_id, InventoryItemUpdate, **kwargs) InventoryItem Update an item
delete_inventory_item(character_id, item_id) None Delete an item

Example

from vclient.models import CharacterCreate, CharacterUpdate, InventoryItemCreate, NoteCreate

# Create a vampire character (preferred method: use model object)
request = CharacterCreate(
    campaign_id="campaign_id",
    character_class="VAMPIRE",
    game_version="V5",
    name_first="Marcus",
    name_last="Blackwood",
    user_player_id="player_user_id"
)
character = await characters.create(request)

# Alternative: pass fields as keyword arguments
character = await characters.create(
    campaign_id="campaign_id",
    character_class="VAMPIRE",
    game_version="V5",
    name_first="Marcus",
    name_last="Blackwood",
    user_player_id="player_user_id"
)

# Update character details
update = CharacterUpdate(name_first="Marcus", name_last="Black")
updated = await characters.update(character.id, update)

# Retrieve roll statistics
stats = await characters.get_statistics(character.id)
print(f"Total rolls: {stats.total_rolls}")
print(f"Success rate: {stats.success_percentage}%")

# Add an inventory item
item_request = InventoryItemCreate(
    name="Silver Dagger",
    type="weapon",
    description="An ornate blade"
)
item = await characters.create_inventory_item(character.id, item_request)

# Create a character note
note_request = NoteCreate(title="Background", content="Born in Victorian London...")
note = await characters.create_note(character.id, note_request)

See Response Models for Character and related types.