Skip to content
Alex edited this page Apr 27, 2026 · 11 revisions

WebSocket API

The module connects to your server as a WebSocket client. Your server sends commands, Foundry executes them and returns results.

Connection

  • Foundry connects to: ws://your-server:port/ws
  • Protocol: JSON messages
  • Auto-reconnect: Configurable interval and max attempts

Message Format

Command (Server → Foundry)

interface Command {
  id: string;      // Unique identifier for correlation
  type: CommandType;
  params: object;
}

Response (Foundry → Server)

interface CommandResponse {
  id: string;      // Same as command ID
  success: boolean;
  data?: object;   // Result on success
  error?: string;  // Error message on failure
}

Commands Reference

Dice Rolling

roll-dice

Execute arbitrary dice formula.

Params:

interface RollDiceParams {
  formula: string;      // "1d20+5", "2d6", "4d6kh3"
  showInChat?: boolean; // Display in Foundry chat (default: false)
  flavor?: string;      // Chat message flavor text
}

Result:

interface RollResult {
  total: number;
  formula: string;
  dice: DiceResult[];
  isCritical?: boolean;
  isFumble?: boolean;
}

interface DiceResult {
  type: string;     // "d20", "d6"
  count: number;
  results: number[];
}

Example:

// Command
{ "id": "1", "type": "roll-dice", "params": { "formula": "1d20+5", "showInChat": true } }

// Response
{ "id": "1", "success": true, "data": { "total": 18, "formula": "1d20+5", "dice": [{ "type": "d20", "count": 1, "results": [13] }] } }

roll-skill

Roll D&D 5e skill check.

Params:

interface RollSkillParams {
  actorId: string;
  skill: SkillKey;       // See skill keys table
  showInChat?: boolean;
}

Skill Keys:

Key Skill Key Skill
acr Acrobatics med Medicine
ani Animal Handling nat Nature
arc Arcana prc Perception
ath Athletics prf Performance
dec Deception per Persuasion
his History rel Religion
ins Insight slt Sleight of Hand
itm Intimidation ste Stealth
inv Investigation sur Survival

Example:

{ "id": "2", "type": "roll-skill", "params": { "actorId": "abc123", "skill": "ste" } }

roll-save

Roll D&D 5e saving throw.

Params:

interface RollSaveParams {
  actorId: string;
  ability: AbilityKey;   // "str", "dex", "con", "int", "wis", "cha"
  showInChat?: boolean;
}

roll-ability

Roll D&D 5e ability check.

Params:

interface RollAbilityParams {
  actorId: string;
  ability: AbilityKey;
  showInChat?: boolean;
}

roll-attack

Roll attack with weapon/spell.

Params:

interface RollAttackParams {
  actorId: string;
  itemId: string;        // Weapon/spell item ID
  advantage?: boolean;
  disadvantage?: boolean;
  showInChat?: boolean;
}

roll-damage

Roll damage for weapon/spell.

Params:

interface RollDamageParams {
  actorId: string;
  itemId: string;
  critical?: boolean;    // Double dice
  showInChat?: boolean;
}

World Info

get-world-info

Get information about the current Foundry world, system, version, entity counts, and available compendiums.

Params:

// No parameters required
interface GetWorldInfoParams {}

Result:

interface WorldInfoResult {
  world: WorldInfoData;
  counts: WorldCounts;
  compendiumMeta: CompendiumMetaSummary[];
}

interface WorldInfoData {
  id: string;
  title: string;
  system: string;            // e.g., "dnd5e"
  systemVersion: string;     // e.g., "4.3.0"
  foundryVersion: string;    // e.g., "13.331"
}

interface WorldCounts {
  journals: number;
  actors: number;
  items: number;
  scenes: number;
}

interface CompendiumMetaSummary {
  id: string;                // e.g., "dnd5e.monsters"
  label: string;             // e.g., "Monsters (SRD)"
  type: string;              // "Actor", "Item", "JournalEntry", etc.
  system: string;
  count: number;             // Number of entries in the compendium
}

Example:

// Command
{ "id": "1", "type": "get-world-info", "params": {} }

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "world": {
      "id": "my-campaign",
      "title": "Curse of Strahd",
      "system": "dnd5e",
      "systemVersion": "4.3.0",
      "foundryVersion": "13.331"
    },
    "counts": { "journals": 42, "actors": 85, "items": 120, "scenes": 15 },
    "compendiumMeta": [
      { "id": "dnd5e.monsters", "label": "Monsters (SRD)", "type": "Actor", "system": "dnd5e", "count": 325 },
      { "id": "dnd5e.items", "label": "Items (SRD)", "type": "Item", "system": "dnd5e", "count": 680 }
    ]
  }
}

Actor Management

get-actors

Get a summary list of all actors in the world.

Params:

// No parameters required
interface GetActorsParams {}

Result:

type GetActorsResult = ActorSummary[];

interface ActorSummary {
  id: string;
  name: string;
  type: string;    // "character", "npc", "vehicle", etc.
  img: string;
}

Example:

// Command
{ "id": "1", "type": "get-actors", "params": {} }

// Response
{
  "id": "1",
  "success": true,
  "data": [
    { "id": "actor-1", "name": "Aragorn", "type": "character", "img": "portraits/aragorn.png" },
    { "id": "actor-2", "name": "Goblin", "type": "npc", "img": "tokens/goblin.png" }
  ]
}

get-actor

Get detailed information about a single actor, including system data and items.

Params:

interface GetActorParams {
  actorId: string;
}

Result:

interface ActorDetailResult {
  id: string;
  name: string;
  type: string;
  img: string;
  system: Record<string, unknown>;  // Full system data (abilities, HP, AC, etc.)
  items: ItemSummary[];
}

interface ItemSummary {
  id: string;
  name: string;
  type: string;
  img: string;
  system: Record<string, unknown>;
}

Example:

// Command
{ "id": "1", "type": "get-actor", "params": { "actorId": "actor-1" } }

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "id": "actor-1",
    "name": "Aragorn",
    "type": "character",
    "img": "portraits/aragorn.png",
    "system": {
      "abilities": { "str": { "value": 18 }, "dex": { "value": 14 } },
      "attributes": { "hp": { "value": 85, "max": 85 }, "ac": { "value": 18 } }
    },
    "items": [
      { "id": "item-1", "name": "Longsword", "type": "weapon", "img": "icons/sword.png", "system": {} }
    ]
  }
}

filter-actors

Search for actors with structured D&D 5e-aware filters. All filters combined with AND, multiple values within array filters with OR. Returns minimal { id, name } summaries — use get-actor for details.

Params:

interface FilterActorsParams {
  // String filters
  name?: string;                          // substring, case-insensitive, trimmed
  type?: string[];                        // strict enum: 'character' | 'npc' | 'vehicle' | 'group'
  creatureType?: string[];                // 14 SRD types: 'aberration', 'beast', 'celestial', 'construct',
                                          // 'dragon', 'elemental', 'fey', 'fiend', 'giant', 'humanoid',
                                          // 'monstrosity', 'ooze', 'plant', 'undead'
  size?: string[];                        // strict codes: 'tiny' | 'sm' | 'med' | 'lg' | 'huge' | 'grg'
  disposition?: string[];                 // 'hostile' | 'neutral' | 'friendly' | 'secret'

  // Boolean
  hasPlayerOwner?: boolean;

  // Numeric range filters (inclusive bounds, both fields optional)
  cr?: { min?: number; max?: number };    // strict D&D values: 0, 0.125, 0.25, 0.5, 1, 2, ..., 30
  level?: { min?: number; max?: number }; // integer ≥ 0 (PC level)
  maxHp?: { min?: number; max?: number };
  currentHp?: { min?: number; max?: number };
  ac?: { min?: number; max?: number };
  abilities?: {
    str?: { min?: number; max?: number };
    dex?: { min?: number; max?: number };
    con?: { min?: number; max?: number };
    int?: { min?: number; max?: number };
    wis?: { min?: number; max?: number };
    cha?: { min?: number; max?: number };
  };

  // Folder
  folder?: {
    id?: string;
    name?: string;
    recursive?: boolean;     // default false
  };

  // Pagination
  limit?: number;            // 1-200, default 50
  offset?: number;           // ≥ 0, default 0
}

Result:

interface FilterActorsResult {
  results: Array<{ id: string; name: string }>;
  total: number;             // total count after filtering, before pagination
  hasMore: boolean;          // total > offset + results.length
}

Behavior notes:

  • All filters combine via AND. Within array filters, values combine via OR.
  • "Silent exclude": if an actor lacks the field being filtered (e.g. PC has no CR, vehicle has no abilities), it's excluded from results without error.
  • Sorting: name ASC, id as tiebreaker. Stable across pages.
  • No filters → returns full list paginated (use get-actors for the simpler full-list contract).
  • Strict validation: invalid CR values, out-of-range limits, unknown enum values produce errors with descriptive messages.
  • World actors only (compendium search is a separate concern).

Examples:

// Find CR 1/4 monsters in the "Goblins" folder
{
  "id": "1",
  "type": "filter-actors",
  "params": {
    "type": ["npc"],
    "cr": { "min": 0.25, "max": 0.25 },
    "folder": { "name": "Goblins", "recursive": true }
  }
}

// Find tough hostile dragons (CR 15+, AC 18+)
{
  "id": "2",
  "type": "filter-actors",
  "params": {
    "creatureType": ["dragon"],
    "disposition": ["hostile"],
    "cr": { "min": 15 },
    "ac": { "min": 18 }
  }
}

// Find PCs by name fragment
{
  "id": "3",
  "type": "filter-actors",
  "params": {
    "type": ["character"],
    "name": "fro"
  }
}

// Response (minimal entries — call get-actor for details)
{
  "id": "3",
  "success": true,
  "data": {
    "results": [
      { "id": "actor-frodo", "name": "Frodo Baggins" }
    ],
    "total": 1,
    "hasMore": false
  }
}

// Pagination through a large set
{
  "id": "4",
  "type": "filter-actors",
  "params": {
    "type": ["npc"],
    "limit": 50,
    "offset": 100
  }
}

create-actor

Create a new actor in the world.

Params:

interface CreateActorParams {
  name: string;
  type: string;           // "character", "npc", "vehicle", etc.
  folder?: string;        // Folder ID
  img?: string;           // Portrait image path
  system?: object;        // System-specific data (abilities, hp, etc.)
}

Result:

interface ActorResult {
  id: string;
  uuid: string;
  name: string;
  type: string;
  img: string;
  folder: string | null;
}

Example:

// Command - create NPC
{
  "id": "1",
  "type": "create-actor",
  "params": {
    "name": "Goblin Archer",
    "type": "npc",
    "system": {
      "abilities": { "str": { "value": 8 }, "dex": { "value": 14 } },
      "attributes": { "hp": { "value": 7, "max": 7 } }
    }
  }
}

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "id": "actor-xyz",
    "uuid": "Actor.actor-xyz",
    "name": "Goblin Archer",
    "type": "npc",
    "img": "icons/svg/mystery-man.svg",
    "folder": null
  }
}

create-actor-from-compendium

Import actor from a compendium pack.

Params:

interface CreateActorFromCompendiumParams {
  packId: string;         // Compendium ID, e.g., "dnd5e.monsters"
  actorId: string;        // Actor ID within compendium
  name?: string;          // Override name
  folder?: string;        // Target folder ID
}

Result: ActorResult

Example:

// Command - import Goblin from SRD
{
  "id": "1",
  "type": "create-actor-from-compendium",
  "params": {
    "packId": "dnd5e.monsters",
    "actorId": "goblin-id-in-compendium",
    "name": "Sneaky Goblin"
  }
}

update-actor

Update actor properties.

Params:

interface UpdateActorParams {
  actorId: string;
  name?: string;
  img?: string;
  folder?: string;
  system?: object;        // Partial update of system data
}

Result: ActorResult

Example:

// Command - update HP
{
  "id": "1",
  "type": "update-actor",
  "params": {
    "actorId": "abc123",
    "system": {
      "attributes": { "hp": { "value": 25 } }
    }
  }
}

delete-actor

Delete actor from the world.

Params:

interface DeleteActorParams {
  actorId: string;
}

Result: DeleteResult


Chat Messages

send-chat-message

Send a message to Foundry VTT chat. Supports in-character, out-of-character, and emote styles. Can optionally whisper to specific users.

Params:

interface SendChatMessageParams {
  content: string;          // Message text (HTML supported)
  speaker?: string;         // Speaker alias override
  actorId?: string;         // Actor ID — sets speaker to actor's name
  flavor?: string;          // Flavor text shown above the message
  whisperTo?: string[];     // User IDs to whisper to
  type?: 'ic' | 'ooc' | 'emote';  // Message style (default: standard)
}

Result:

interface SendChatMessageResult {
  messageId: string;
  sent: boolean;
}

Example:

// Command - in-character speech
{
  "id": "1",
  "type": "send-chat-message",
  "params": {
    "content": "You shall not pass!",
    "actorId": "gandalf-actor-id",
    "type": "ic"
  }
}

// Response
{ "id": "1", "success": true, "data": { "messageId": "msg-001", "sent": true } }

// Command - whisper to player
{
  "id": "2",
  "type": "send-chat-message",
  "params": {
    "content": "You notice a hidden trap in the floor.",
    "whisperTo": ["player-user-id"],
    "flavor": "Perception DC 15"
  }
}

get-chat-messages

Retrieve chat messages with filtering and pagination. Returns messages from most recent, with configurable limit.

Params:

interface GetChatMessagesParams {
  limit?: number;           // Number of messages to return (default: 20, max: 100)
  since?: string;           // Message ID — return messages after this one
  before?: string;          // Message ID — return messages before this one
  includeRolls?: boolean;   // Include roll formula/total summaries (default: false)
  authorId?: string;        // Filter by author user ID
  actorId?: string;         // Filter by speaker actor ID
  type?: 'ic' | 'ooc' | 'emote' | 'roll';  // Filter by message style
  search?: string;          // Full-text search in message content
}

Result:

interface GetChatMessagesResult {
  messages: ChatMessageData[];
  total: number;            // Total messages in chat log
  hasMore: boolean;         // More messages available beyond limit
}

interface ChatMessageData {
  id: string;
  timestamp: number;
  author: {
    userId: string;
    name: string;
  };
  speaker: ChatMessageSpeaker;
  content: string;          // HTML stripped to plain text
  flavor: string | null;
  style: 'other' | 'ooc' | 'ic' | 'emote';
  isRoll: boolean;
  rolls?: ChatMessageRollSummary[];   // Only when includeRolls: true
  whisper: string[];
  isWhisper: boolean;
}

interface ChatMessageSpeaker {
  alias: string;
  actorId: string | null;
  tokenId: string | null;
}

interface ChatMessageRollSummary {
  formula: string;
  total: number;
}

Example:

// Command - get last 10 messages with rolls
{
  "id": "1",
  "type": "get-chat-messages",
  "params": { "limit": 10, "includeRolls": true }
}

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "messages": [
      {
        "id": "msg-100",
        "timestamp": 1713200000,
        "author": { "userId": "gm-user", "name": "Game Master" },
        "speaker": { "alias": "GM", "actorId": null, "tokenId": null },
        "content": "Roll for initiative!",
        "flavor": null,
        "style": "ooc",
        "isRoll": false,
        "whisper": [],
        "isWhisper": false
      }
    ],
    "total": 250,
    "hasMore": true
  }
}

// Command - search for messages mentioning "dragon"
{ "id": "2", "type": "get-chat-messages", "params": { "search": "dragon", "limit": 5 } }

update-chat-message

Update the content or flavor of an existing chat message.

Params:

interface UpdateChatMessageParams {
  messageId: string;
  content?: string;         // New message content
  flavor?: string;          // New flavor text
}

Result:

interface SendChatMessageResult {
  messageId: string;
  sent: boolean;
}

Example:

// Command
{ "id": "1", "type": "update-chat-message", "params": { "messageId": "msg-100", "content": "Updated text" } }

// Response
{ "id": "1", "success": true, "data": { "messageId": "msg-100", "sent": true } }

delete-chat-message

Delete a single chat message by ID.

Params:

interface DeleteChatMessageParams {
  messageId: string;
}

Result: DeleteResult

Example:

{ "id": "1", "type": "delete-chat-message", "params": { "messageId": "msg-100" } }
{ "id": "1", "success": true, "data": { "deleted": true } }

clear-chat

Delete all messages from the chat log.

Params:

// No parameters required

Result:

interface ClearChatResult {
  deletedCount: number;
}

Example:

// Command
{ "id": "1", "type": "clear-chat", "params": {} }

// Response
{ "id": "1", "success": true, "data": { "deletedCount": 142 } }

export-chat

Export the entire chat log as text or JSON.

Params:

interface ExportChatParams {
  format?: 'text' | 'json';  // Default: 'text'
}

Result:

interface ExportChatResult {
  content: string;           // Exported content (plain text or JSON string)
  messageCount: number;
}

Example:

// Command - export as text
{ "id": "1", "type": "export-chat", "params": { "format": "text" } }

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "content": "[Game Master] Roll for initiative!\n[Aragorn] I attack the goblin!",
    "messageCount": 2
  }
}

// Command - export as JSON
{ "id": "2", "type": "export-chat", "params": { "format": "json" } }

Journal Management

get-journals

Get a list of all journal entries in the world.

Params:

// No parameters required
interface GetJournalsParams {}

Result:

type GetJournalsResult = JournalData[];

interface JournalData {
  id: string;
  uuid: string;
  name: string;
  folder: string | null;
  pages: JournalPageData[];
}

interface JournalPageData {
  id: string;
  name: string;
  type: string;           // "text", "image", "video", "pdf"
  text: string | null;
  markdown: string | null;
  enrichedText: string | null;  // Foundry-enriched HTML (@UUID links resolved, inline rolls, etc.)
  src: string | null;           // Source URL for image/video/pdf pages
}

Example:

// Command
{ "id": "1", "type": "get-journals", "params": {} }

// Response
{
  "id": "1",
  "success": true,
  "data": [
    {
      "id": "journal-1",
      "uuid": "JournalEntry.journal-1",
      "name": "Session Notes",
      "folder": null,
      "pages": [
        { "id": "page-1", "name": "Session 1", "type": "text", "text": "<p>The party met at the tavern...</p>", "markdown": null }
      ]
    }
  ]
}

get-journal

Get a single journal entry with full page content.

Params:

interface GetJournalParams {
  journalId: string;
}

Result: JournalData

Example:

{ "id": "1", "type": "get-journal", "params": { "journalId": "journal-1" } }

create-journal

Create new journal entry.

Params:

interface CreateJournalParams {
  name: string;
  folder?: string;              // Folder ID
  content?: string;             // HTML content for first page
  pageType?: "text" | "image" | "video" | "pdf";
}

Result:

interface JournalResult {
  id: string;
  name: string;
  folder: string | null;
  pages: JournalPageResult[];
}

update-journal

Update journal properties.

Params:

interface UpdateJournalParams {
  journalId: string;
  name?: string;
  folder?: string;
}

delete-journal

Delete journal entry.

Params:

interface DeleteJournalParams {
  journalId: string;
}

Result:

interface DeleteResult {
  deleted: boolean;
}

create-journal-page

Add page to existing journal.

Params:

interface CreateJournalPageParams {
  journalId: string;
  name: string;
  type?: "text" | "image" | "video" | "pdf";
  content?: string;              // HTML for text pages
  src?: string;                  // Source URL for image/video/pdf pages
}

update-journal-page

Update page content.

Params:

interface UpdateJournalPageParams {
  journalId: string;
  pageId: string;
  name?: string;
  content?: string;
  src?: string;                  // Source URL for image/video/pdf pages
}

delete-journal-page

Remove page from journal.

Params:

interface DeleteJournalPageParams {
  journalId: string;
  pageId: string;
}

show-journal

Show a journal entry or specific page to players. Pushes the journal to their screens.

Params:

interface ShowJournalParams {
  journalId: string;
  pageId?: string;         // Show specific page (default: entire journal)
  force?: boolean;         // Override permissions (default: false)
  users?: string[];        // Specific user IDs (default: all players)
}

Result:

interface ShowJournalResult {
  shown: boolean;
  journalId: string;
  journalName: string;
  pageId?: string;
}

Example:

// Command - show journal to all players
{ "id": "1", "type": "show-journal", "params": { "journalId": "journal-quest" } }

// Response
{ "id": "1", "success": true, "data": { "shown": true, "journalId": "journal-quest", "journalName": "Quest Log" } }

// Command - show specific page, force override permissions
{
  "id": "2",
  "type": "show-journal",
  "params": {
    "journalId": "journal-quest",
    "pageId": "page-handout",
    "force": true
  }
}

// Command - show to specific player
{
  "id": "3",
  "type": "show-journal",
  "params": {
    "journalId": "journal-secret",
    "users": ["player-rogue-id"]
  }
}

Combat Tracker

create-combat

Create new combat encounter.

Params:

interface CreateCombatParams {
  sceneId?: string;    // Defaults to active scene
  activate?: boolean;  // Make active combat
}

Result:

interface CombatResult {
  id: string;
  round: number;
  turn: number;
  started: boolean;
  combatants: CombatantResult[];
  current: CombatantResult | null;
}

interface CombatantResult {
  id: string;
  actorId: string;
  tokenId: string | null;
  name: string;
  img: string;
  initiative: number | null;
  defeated: boolean;
  hidden: boolean;
}

add-combatant

Add actor to combat.

Params:

interface AddCombatantParams {
  actorId: string;
  combatId?: string;      // Defaults to active combat
  tokenId?: string;
  initiative?: number;    // Pre-set initiative
  hidden?: boolean;
}

remove-combatant

Remove from combat.

Params:

interface RemoveCombatantParams {
  combatantId: string;
  combatId?: string;
}

start-combat

Begin combat (sets round to 1).

Params:

interface CombatIdParams {
  combatId?: string;
}

end-combat

End and delete combat. Shows confirmation dialog in Foundry VTT v13.

Params: CombatIdParams


delete-combat

Delete combat directly without confirmation dialog. Useful for programmatic combat management, especially in Foundry VTT v13 where end-combat shows a confirmation dialog.

Params: CombatIdParams

Result:

interface DeleteResult {
  deleted: boolean;
}

Example:

// Command
{ "id": "1", "type": "delete-combat", "params": {} }

// Response
{ "id": "1", "success": true, "data": { "deleted": true } }

// With specific combat ID
{ "id": "2", "type": "delete-combat", "params": { "combatId": "abc123" } }

next-turn / previous-turn

Navigate turn order.

Params: CombatIdParams


set-turn

Set the current turn to a specific combatant.

Params:

interface SetTurnParams {
  combatantId: string;    // Combatant to set as current turn
  combatId?: string;
}

Result: CombatResult

Example:

// Command
{ "id": "1", "type": "set-turn", "params": { "combatantId": "combatant-xyz" } }

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "id": "combat-1",
    "round": 2,
    "turn": 3,
    "started": true,
    "combatants": [],
    "current": { "id": "combatant-xyz", "actorId": "actor-1", "tokenId": "token-1", "name": "Goblin", "img": "tokens/goblin.png", "initiative": 15, "defeated": false, "hidden": false }
  }
}

get-combat-state

Get current combat state.

Params: CombatIdParams

Result: CombatResult


get-combat-turn-context

Get rich contextual information about the current combat turn, including the active combatant's stats, nearby tokens with distances, line-of-sight data, and an ASCII map of the battlefield zoomed around the current combatant.

Params:

interface GetCombatTurnContextParams {
  combatId?: string;       // Defaults to active combat
}

Result:

interface CombatTurnContext {
  round: number;
  turn: number;
  currentCombatant: TurnCombatantInfo;
  nearbyTokens: NearbyTokenInfo[];
  asciiMap: string;        // ASCII art map of the battlefield (zoomed to 12-grid radius)
}

interface TurnCombatantInfo {
  id: string;              // Combatant ID
  actorId: string;
  tokenId: string;
  name: string;
  gridX: number;           // Grid coordinates
  gridY: number;
  hp?: { value: number; max: number };
  ac?: number;
  conditions: string[];    // Active status effect IDs
}

interface NearbyTokenInfo {
  tokenId: string;
  actorId: string | null;
  name: string;
  gridX: number;
  gridY: number;
  distanceFt: number;      // Distance in feet (Chebyshev / grid distance)
  disposition: string;     // "hostile", "neutral", "friendly"
  hp?: { value: number; max: number };
  ac?: number;
  conditions: string[];
  lineOfSight: boolean;    // Whether the current combatant can see this token
}

Example:

// Command
{ "id": "1", "type": "get-combat-turn-context", "params": {} }

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "round": 2,
    "turn": 0,
    "currentCombatant": {
      "id": "combatant-1",
      "actorId": "actor-fighter",
      "tokenId": "token-fighter",
      "name": "Fighter",
      "gridX": 5,
      "gridY": 5,
      "hp": { "value": 45, "max": 52 },
      "ac": 18,
      "conditions": []
    },
    "nearbyTokens": [
      {
        "tokenId": "token-goblin-1",
        "actorId": "actor-goblin",
        "name": "Goblin",
        "gridX": 6,
        "gridY": 5,
        "distanceFt": 5,
        "disposition": "hostile",
        "hp": { "value": 5, "max": 7 },
        "ac": 15,
        "conditions": [],
        "lineOfSight": true
      }
    ],
    "asciiMap": "... (ASCII representation of battlefield) ..."
  }
}

Initiative

roll-initiative

Roll initiative for specific combatants.

Params:

interface RollInitiativeParams {
  combatantIds: string[];
  combatId?: string;
  formula?: string;      // Custom formula, uses system default if omitted
}

Result:

interface InitiativeRollResult {
  results: Array<{
    combatantId: string;
    name: string;
    initiative: number;
  }>;
}

set-initiative

Manually set initiative value.

Params:

interface SetInitiativeParams {
  combatantId: string;
  initiative: number;
  combatId?: string;
}

roll-all-initiative

Roll initiative for all combatants.

Params:

interface RollAllInitiativeParams {
  combatId?: string;
  formula?: string;
  npcsOnly?: boolean;   // Roll only for NPCs
}

Combatant Updates

update-combatant

Update combatant properties.

Params:

interface UpdateCombatantParams {
  combatantId: string;
  combatId?: string;
  initiative?: number;
  defeated?: boolean;
  hidden?: boolean;
}

set-combatant-defeated

Mark combatant as defeated.

Params:

interface SetCombatantDefeatedParams {
  combatantId: string;
  defeated: boolean;
  combatId?: string;
}

toggle-combatant-visibility

Toggle hidden status.

Params:

interface ToggleCombatantVisibilityParams {
  combatantId: string;
  combatId?: string;
}

Token Management

create-token

Place token on scene.

Params:

interface CreateTokenParams {
  actorId: string;
  x: number;
  y: number;
  sceneId?: string;      // Defaults to active scene
  hidden?: boolean;
  elevation?: number;
  rotation?: number;     // Degrees
  scale?: number;
}

Result:

interface TokenResult {
  id: string;
  name: string;
  actorId: string | null;
  x: number;
  y: number;
  elevation: number;
  rotation: number;
  hidden: boolean;
  img: string;
  disposition: number;   // -1: hostile, 0: neutral, 1: friendly
}

delete-token

Remove token from scene.

Params:

interface DeleteTokenParams {
  tokenId: string;
  sceneId?: string;
}

move-token

Move token to new position. Uses A* pathfinding to navigate around walls and optionally through doors.

Params:

interface MoveTokenParams {
  tokenId: string;
  x: number;
  y: number;
  sceneId?: string;
  elevation?: number;
  rotation?: number;
  animate?: boolean;       // Default: true
  canOpenDoors?: boolean;  // Allow opening doors along path
}

Result:

interface TokenResult {
  id: string;
  name: string;
  actorId: string | null;
  x: number;
  y: number;
  width: number;
  height: number;
  elevation: number;
  rotation: number;
  hidden: boolean;
  img: string;
  disposition: number;
  hp?: { value: number; max: number };
  ac?: number;
  conditions: string[];
  pathCost?: number;        // Movement cost in grid units (when pathfinding used)
  doorsOpened?: string[];   // Wall IDs of doors opened during movement
}

update-token

Update token properties.

Params:

interface UpdateTokenParams {
  tokenId: string;
  sceneId?: string;
  hidden?: boolean;
  elevation?: number;
  rotation?: number;
  scale?: number;
  name?: string;
  displayName?: number;
  disposition?: number;  // -1, 0, 1
  lockRotation?: boolean;
}

get-scene-tokens

Get all tokens from scene.

Params:

interface GetSceneTokensParams {
  sceneId?: string;      // Defaults to active scene
}

Result:

interface SceneTokensResult {
  sceneId: string;
  sceneName: string;
  tokens: TokenResult[];
}

Scene Management

get-scene

Get detailed information about a scene, including grid, darkness, notes, walls, lights, tiles, drawings, regions, and tokens with grid coordinates.

Params:

interface GetSceneParams {
  sceneId?: string;          // Defaults to active scene
  includeScreenshot?: boolean; // Include base64 screenshot of the scene
}

Result:

interface SceneDetailResult {
  id: string;
  name: string;
  active: boolean;
  img: string;
  width: number;
  height: number;
  grid: {
    size: number;        // Grid size in pixels (default: 100)
    type: number;        // 1 = square, 2 = hex rows, 3 = hex columns
    units: string;       // "ft", "m", etc.
    distance: number;    // Distance per grid square (e.g., 5)
  };
  darkness: number;      // 0 (bright) to 1 (fully dark)
  notes: SceneNote[];
  walls: SceneWall[];
  lights: SceneLight[];
  tiles: SceneTile[];
  drawings: SceneDrawing[];
  regions: SceneRegion[];
  tokens: SceneTokenSummary[];
  asciiMap: string;      // ASCII art representation of the scene
  screenshot?: SceneScreenshot;  // Only when includeScreenshot: true
}

interface SceneScreenshot {
  image: string;         // Base64-encoded image data
  mimeType: string;      // e.g., "image/webp"
  width: number;
  height: number;
}

interface SceneNote {
  x: number;
  y: number;
  text: string;
  label: string;
  entryId: string | null;
}

interface SceneWall {
  id: string;
  c: number[];           // [x1, y1, x2, y2]
  move: number;          // 0 = none, 20 = blocks movement
  sense: number;         // 0 = none, 20 = blocks vision
  door: number;          // 0 = wall, 1 = door, 2 = secret door
  ds: number;            // Door state: 0 = closed, 1 = open, 2 = locked
}

interface SceneLight {
  x: number;
  y: number;
  bright: number;        // Bright light radius in grid units
  dim: number;           // Dim light radius in grid units
  color: string | null;  // e.g., "#ff9900", null = white
  angle: number;         // Emission angle (360 = omnidirectional)
  walls: boolean;        // Blocked by walls
  hidden: boolean;
}

interface SceneTile {
  x: number;
  y: number;
  width: number;
  height: number;
  img: string;           // Image file path
  hidden: boolean;
  elevation: number;
  rotation: number;      // Degrees
}

interface SceneDrawing {
  x: number;
  y: number;
  shape: {
    type: string;        // "r" = rectangle, "e" = ellipse, "p" = polygon, "f" = freehand
    width: number;
    height: number;
    points: number[];    // Vertex coordinates [x1,y1,x2,y2,...] for polygon/freehand
  };
  text: string;
  hidden: boolean;
  fillColor: string | null;
  strokeColor: string | null;
}

interface SceneRegion {
  id: string;
  name: string;          // e.g., "Throne Room", "Trap Zone"
  color: string | null;
  shapes: Array<{ type: string }>;
}

interface SceneTokenSummary {
  id: string;
  name: string;
  actorId: string | null;
  gridX: number;         // Grid position (Math.floor(x / gridSize))
  gridY: number;
  x: number;             // Original pixel position
  y: number;
  elevation: number;
  hidden: boolean;
  disposition: number;   // -1: hostile, 0: neutral, 1: friendly
  hp?: { value: number; max: number };
  ac?: number;
  conditions: string[];
}

Example:

// Command - get active scene
{ "id": "1", "type": "get-scene", "params": {} }

// Command - get specific scene
{ "id": "2", "type": "get-scene", "params": { "sceneId": "scene-abc" } }

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "id": "scene-abc",
    "name": "Tavern - Ground Floor",
    "active": true,
    "img": "scenes/tavern.jpg",
    "width": 4000,
    "height": 3000,
    "grid": { "size": 100, "type": 1, "units": "ft", "distance": 5 },
    "darkness": 0.3,
    "notes": [
      { "x": 500, "y": 300, "text": "Bar counter", "label": "Bar", "entryId": null },
      { "x": 1200, "y": 800, "text": "Secret trapdoor", "label": "Trapdoor", "entryId": "journal-cellar" }
    ],
    "walls": [
      { "id": "wall-1", "c": [0, 0, 4000, 0], "move": 20, "sense": 20, "door": 0, "ds": 0 },
      { "id": "wall-2", "c": [800, 500, 800, 700], "move": 20, "sense": 20, "door": 1, "ds": 0 }
    ],
    "lights": [
      { "x": 500, "y": 500, "bright": 20, "dim": 40, "color": "#ff9900", "angle": 360, "walls": true, "hidden": false }
    ],
    "tiles": [
      { "x": 200, "y": 300, "width": 100, "height": 100, "img": "tiles/table.png", "hidden": false, "elevation": 0, "rotation": 0 }
    ],
    "drawings": [
      { "x": 400, "y": 400, "shape": { "type": "r", "width": 200, "height": 100, "points": [] }, "text": "", "hidden": false, "fillColor": "#00ff00", "strokeColor": "#000000" }
    ],
    "regions": [
      { "id": "region1", "name": "Trap Zone", "color": "#ff0000", "shapes": [{ "type": "rectangle" }] }
    ],
    "tokens": [
      { "id": "token-1", "name": "Goblin", "actorId": "actor-1", "gridX": 2, "gridY": 3, "x": 250, "y": 350, "elevation": 0, "hidden": false, "disposition": -1 },
      { "id": "token-2", "name": "Fighter", "actorId": "actor-2", "gridX": 5, "gridY": 5, "x": 500, "y": 500, "elevation": 0, "hidden": false, "disposition": 1 }
    ],
    "asciiMap": "... (ASCII map) ..."
  }
}

get-scenes-list

Get a summary list of all scenes in the world.

Params:

interface GetScenesListParams {
  // No parameters
}

Result:

interface SceneListResult {
  scenes: SceneSummary[];
}

interface SceneSummary {
  id: string;
  name: string;
  active: boolean;
  img: string;
}

Example:

// Command
{ "id": "1", "type": "get-scenes-list", "params": {} }

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "scenes": [
      { "id": "scene-1", "name": "Tavern - Ground Floor", "active": true, "img": "scenes/tavern.jpg" },
      { "id": "scene-2", "name": "Dark Forest", "active": false, "img": "scenes/forest.jpg" },
      { "id": "scene-3", "name": "Dragon's Lair", "active": false, "img": "scenes/lair.jpg" }
    ]
  }
}

activate-scene

Switch the active scene. All players will be moved to this scene.

Params:

interface ActivateSceneParams {
  sceneId: string;       // Required - scene ID to activate
}

Result:

interface ActivateSceneResult {
  id: string;
  name: string;
  active: boolean;       // Always true after activation
}

Example:

// Command
{ "id": "1", "type": "activate-scene", "params": { "sceneId": "scene-2" } }

// Response
{ "id": "1", "success": true, "data": { "id": "scene-2", "name": "Dark Forest", "active": true } }

capture-scene

Capture a screenshot of the current active scene canvas, including a grid overlay. Returns a base64-encoded WebP image.

Params:

// No parameters required
interface CaptureSceneParams {}

Result:

interface CaptureSceneResult {
  sceneId: string;
  sceneName: string;
  image: string;         // Base64-encoded image data (no data URI prefix)
  mimeType: string;      // "image/webp"
  width: number;         // Canvas width in pixels
  height: number;        // Canvas height in pixels
}

Example:

// Command
{ "id": "1", "type": "capture-scene", "params": {} }

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "sceneId": "scene-abc",
    "sceneName": "Tavern - Ground Floor",
    "image": "UklGRh4AAABXRUJQVlA4IBIAAAAwAQCdASoBAAEAAQ...",
    "mimeType": "image/webp",
    "width": 1920,
    "height": 1080
  }
}

Item Management

get-items

Get a list of all world-level items (not in actors' inventories).

Params:

// No parameters required
interface GetItemsParams {}

Result:

type GetItemsResult = ItemData[];

interface ItemData {
  id: string;
  uuid?: string;
  name: string;
  type: string;
  img: string;
  folder?: string | null;
  system: Record<string, unknown>;
}

Example:

// Command
{ "id": "1", "type": "get-items", "params": {} }

// Response
{
  "id": "1",
  "success": true,
  "data": [
    { "id": "item-1", "name": "Healing Potion", "type": "consumable", "img": "icons/potions/healing.png", "system": { "quantity": 5 } },
    { "id": "item-2", "name": "Longsword +1", "type": "weapon", "img": "icons/weapons/sword.png", "system": {} }
  ]
}

get-item

Get detailed information about a single world-level item.

Params:

interface GetItemParams {
  itemId: string;
}

Result: ItemData

Example:

{ "id": "1", "type": "get-item", "params": { "itemId": "item-1" } }

get-actor-items

Get items from actor's inventory with optional filtering.

Params:

interface GetActorItemsParams {
  actorId: string;
  type?: string;           // Filter by item type (weapon, spell, consumable, etc.)
  equipped?: boolean;      // Filter by equipped status
  hasActivities?: boolean; // Filter items with activities (D&D 5e 2024)
}

Result:

interface ActorItemsResult {
  actorId: string;
  actorName: string;
  items: ItemDetailSummary[];
}

interface ItemDetailSummary {
  id: string;
  name: string;
  type: string;
  img: string;
  equipped: boolean;
  quantity: number;
  hasActivities: boolean;
  activityTypes: string[];  // e.g., ["attack", "damage", "save"]
  description: string;
  damage: object | null;
  range: object | null;
}

Example:

// Command - get all weapons
{ "id": "1", "type": "get-actor-items", "params": { "actorId": "abc123", "type": "weapon" } }

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "actorId": "abc123",
    "actorName": "Aragorn",
    "items": [
      {
        "id": "item-456",
        "name": "Longsword",
        "type": "weapon",
        "img": "icons/weapons/swords/sword.png",
        "equipped": true,
        "quantity": 1,
        "hasActivities": true,
        "activityTypes": ["attack", "damage"],
        "description": "A fine longsword",
        "damage": {},
        "range": {}
      }
    ]
  }
}

use-item

Use/activate an item (cast spell, use consumable, attack with weapon).

Params:

interface UseItemParams {
  actorId: string;
  itemId: string;
  activityId?: string;     // Specific activity ID (D&D 5e 2024)
  activityType?: string;   // Activity type filter (attack, damage, save, heal)
  consume?: boolean;       // Consume resources (default: true)
  scaling?: number;        // Spell slot level for scaling
  showInChat?: boolean;    // Show in chat (default: true)
}

Result:

interface UseItemResult {
  itemId: string;
  itemName: string;
  itemType: string;
  activityUsed?: ActivityInfo;
  rolls: RollResult[];
  chatMessageId?: string;
}

interface ActivityInfo {
  id: string;
  name: string;
  type: string;
}

Example:

// Command - cast Fireball at 4th level
{
  "id": "1",
  "type": "use-item",
  "params": {
    "actorId": "abc123",
    "itemId": "spell-fireball",
    "scaling": 4,
    "showInChat": true
  }
}

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "itemId": "spell-fireball",
    "itemName": "Fireball",
    "itemType": "spell",
    "activityUsed": { "id": "act-1", "name": "Cast", "type": "save" },
    "rolls": [{ "total": 32, "formula": "9d6", "dice": [{ "type": "d6", "count": 9, "results": [4,5,3,6,2,4,3,3,2] }] }],
    "chatMessageId": "msg-xyz"
  }
}

activate-item

Activate an item natively, triggering the full Foundry automation pipeline. Unlike use-item, this command does not suppress hooks or dialogs, allowing automation modules like Midi-QOL to intercept the call and execute the full combat sequence (attack roll -> AC check -> damage -> HP reduction -> effects).

Supports programmatic targeting -- set targetTokenIds so automation modules know which tokens to resolve attacks against.

Params:

interface ActivateItemParams {
  actorId: string;           // ID of the actor using the item
  itemId: string;            // ID of the item in the actor's inventory
  activityId?: string;       // Specific activity ID (D&D 5e 2024 activities system)
  activityType?: string;     // Activity type filter: "attack", "damage", "save", "heal", "check", "utility"
  targetTokenIds?: string[]; // Token IDs on the active scene to set as targets before activation
  templatePosition?: { x: number; y: number; direction?: number };  // Position for spell template
  spellLevel?: number;       // Cast at a specific spell level
}

Result:

interface ActivateItemResult {
  itemId: string;            // ID of the used item
  itemName: string;          // Display name of the item (e.g., "Longsword", "Fireball")
  itemType: string;          // Item type: "weapon", "spell", "consumable", "equipment", "feat", etc.
  activityUsed?: ActivityInfo; // Present when item has D&D 5e activities. Absent when item has no activities.
  activated: boolean;        // Always true on success
  targetsSet: number;        // Number of targets set before activation (0 if targetTokenIds not provided)
  rolls: RollResult[];       // Dice rolls returned by Foundry's native item.use() / activity.use()
  chatMessageId?: string;    // ID of the chat message created in Foundry. Present when Foundry creates a chat card.
  workflow?: MidiWorkflowResult; // Midi-QOL automation results. ONLY present when Midi-QOL module is installed and active.
}

interface ActivityInfo {
  id: string;                // Activity ID within the item
  name: string;              // Activity display name (e.g., "Attack", "Cast", "Heal")
  type: string;              // Activity type: "attack", "damage", "save", "heal", "check", "utility"
}

interface RollResult {
  total: number;             // Final roll total (e.g., 18 for "1d20+5" roll of 13)
  formula: string;           // Roll formula as string (e.g., "1d20+5", "2d6+3")
  dice: DiceResult[];        // Individual dice breakdowns
  isCritical?: boolean;      // true if natural 20 on d20 attack roll
  isFumble?: boolean;        // true if natural 1 on d20 attack roll
}

interface DiceResult {
  type: string;              // Dice type: "d20", "d6", "d8", "d10", "d12", etc.
  count: number;             // Number of dice rolled (e.g., 2 for "2d6")
  results: number[];         // Individual die results (e.g., [4, 6] for 2d6)
}

interface MidiWorkflowResult {
  attackTotal: number | undefined;      // Total attack roll value. undefined for non-attack items (potions, spells with saves only).
  damageTotal: number | undefined;      // Total damage dealt. undefined if attack missed or no damage component.
  isCritical: boolean;                  // true if the attack was a critical hit (natural 20)
  isFumble: boolean;                    // true if the attack was a fumble (natural 1)
  hitTargetIds: string[];               // Token IDs that were HIT by the attack. Empty array if attack missed or spell with saves.
  saveTargetIds: string[];              // Token IDs that SUCCEEDED their saving throw. For spells like Fireball.
  failedSaveTargetIds: string[];        // Token IDs that FAILED their saving throw. These take full damage/effects.
}

Presence rules for optional fields:

Field When present When absent
activityUsed Item has D&D 5e activities Item has no activities (falls back to item.use())
chatMessageId Foundry created a chat card No chat message was created
rolls[] Always present Empty array [] if no rolls (Midi-QOL handles rolling)
workflow Midi-QOL module is installed, active, and completed Midi-QOL not installed, inactive, or timed out (5s)
workflow.attackTotal Attack item (weapon, spell attack) Non-attack items (potion, spell with save only)
workflow.damageTotal Attack hit or AoE damage applied Attack missed with no damage

Difference from use-item:

use-item activate-item
Foundry hooks Suppressed (configure: false, shiftKey: true) Native (not suppressed)
Midi-QOL Does not trigger Full automation pipeline
Targeting Not supported targetTokenIds sets targets before activation
Returns rolls Always (from suppressed Foundry call) From native call + Midi-QOL workflow data
Dialogs Suppressed May appear (native Foundry behavior)
Use case Silent/programmatic operations Combat actions, spellcasting, item usage with full visualization

Midi-QOL detection: The module checks game.modules.get('midi-qol')?.active before activation. If Midi-QOL is active, it registers a Hooks.once('midi-qol.RollComplete') listener before calling use(), then awaits the workflow result with a 5-second timeout. If Midi-QOL is not installed, no hooks are registered and workflow will be absent -- zero overhead.

Examples:

// === Melee attack with Midi-QOL active ===

// Command
{
  "id": "1",
  "type": "activate-item",
  "params": {
    "actorId": "goblin-actor",
    "itemId": "scimitar-id",
    "targetTokenIds": ["fighter-token"]
  }
}

// Response -- attack HIT
{
  "id": "1",
  "success": true,
  "data": {
    "itemId": "scimitar-id",
    "itemName": "Scimitar",
    "itemType": "weapon",
    "activityUsed": { "id": "act-1", "name": "Attack", "type": "attack" },
    "activated": true,
    "targetsSet": 1,
    "rolls": [
      {
        "total": 17,
        "formula": "1d20+4",
        "dice": [{ "type": "d20", "count": 1, "results": [13] }]
      }
    ],
    "chatMessageId": "msg-abc",
    "workflow": {
      "attackTotal": 17,
      "damageTotal": 8,
      "isCritical": false,
      "isFumble": false,
      "hitTargetIds": ["fighter-token"],
      "saveTargetIds": [],
      "failedSaveTargetIds": []
    }
  }
}

// === Critical hit ===
{
  "id": "2",
  "success": true,
  "data": {
    "itemId": "scimitar-id",
    "itemName": "Scimitar",
    "itemType": "weapon",
    "activityUsed": { "id": "act-1", "name": "Attack", "type": "attack" },
    "activated": true,
    "targetsSet": 1,
    "rolls": [
      { "total": 24, "formula": "1d20+4", "dice": [{ "type": "d20", "count": 1, "results": [20] }], "isCritical": true }
    ],
    "chatMessageId": "msg-def",
    "workflow": {
      "attackTotal": 24,
      "damageTotal": 14,
      "isCritical": true,
      "isFumble": false,
      "hitTargetIds": ["fighter-token"],
      "saveTargetIds": [],
      "failedSaveTargetIds": []
    }
  }
}

// === Attack MISSED ===
{
  "id": "3",
  "success": true,
  "data": {
    "itemId": "scimitar-id",
    "itemName": "Scimitar",
    "itemType": "weapon",
    "activityUsed": { "id": "act-1", "name": "Attack", "type": "attack" },
    "activated": true,
    "targetsSet": 1,
    "rolls": [
      { "total": 8, "formula": "1d20+4", "dice": [{ "type": "d20", "count": 1, "results": [4] }] }
    ],
    "chatMessageId": "msg-ghi",
    "workflow": {
      "attackTotal": 8,
      "isCritical": false,
      "isFumble": false,
      "hitTargetIds": [],
      "saveTargetIds": [],
      "failedSaveTargetIds": []
    }
  }
}

// === Fireball (save-based AoE) with Midi-QOL ===
{
  "id": "4",
  "type": "activate-item",
  "params": {
    "actorId": "wizard-actor",
    "itemId": "fireball-id",
    "targetTokenIds": ["goblin-1", "goblin-2", "goblin-3"]
  }
}

// Response -- 2 failed saves, 1 saved
{
  "id": "4",
  "success": true,
  "data": {
    "itemId": "fireball-id",
    "itemName": "Fireball",
    "itemType": "spell",
    "activityUsed": { "id": "act-1", "name": "Cast", "type": "save" },
    "activated": true,
    "targetsSet": 3,
    "rolls": [],
    "chatMessageId": "msg-jkl",
    "workflow": {
      "damageTotal": 28,
      "isCritical": false,
      "isFumble": false,
      "hitTargetIds": [],
      "saveTargetIds": ["goblin-2"],
      "failedSaveTargetIds": ["goblin-1", "goblin-3"]
    }
  }
}

// === Healing Potion (no target, no Midi-QOL workflow) ===
{
  "id": "5",
  "type": "activate-item",
  "params": {
    "actorId": "fighter-actor",
    "itemId": "healing-potion-id"
  }
}

// Response -- no targets, basic rolls only
{
  "id": "5",
  "success": true,
  "data": {
    "itemId": "healing-potion-id",
    "itemName": "Potion of Healing",
    "itemType": "consumable",
    "activated": true,
    "targetsSet": 0,
    "rolls": [
      { "total": 7, "formula": "2d4+2", "dice": [{ "type": "d4", "count": 2, "results": [3, 2] }] }
    ],
    "chatMessageId": "msg-mno"
  }
}

// === Without Midi-QOL installed (vanilla Foundry) ===
{
  "id": "6",
  "success": true,
  "data": {
    "itemId": "scimitar-id",
    "itemName": "Scimitar",
    "itemType": "weapon",
    "activityUsed": { "id": "act-1", "name": "Attack", "type": "attack" },
    "activated": true,
    "targetsSet": 1,
    "rolls": [
      { "total": 15, "formula": "1d20+4", "dice": [{ "type": "d20", "count": 1, "results": [11] }] }
    ],
    "chatMessageId": "msg-pqr"
  }
}

add-item-to-actor

Create a new item directly in an actor's inventory.

Params:

interface AddItemToActorParams {
  actorId: string;
  name: string;
  type: string;              // "weapon", "equipment", "consumable", "loot", "spell", etc.
  img?: string;              // Item icon path
  system?: ItemSystemData;   // System-specific data
}

interface ItemSystemData {
  description?: { value: string };
  quantity?: number;
  weight?: { value: number; units?: string };
  price?: { value: number; denomination?: string };
  rarity?: string;           // "common", "uncommon", "rare", "veryRare", "legendary"
  identified?: boolean;
  equipped?: boolean;
  attunement?: number;
}

Result:

interface ItemResult {
  id: string;
  name: string;
  type: string;
  img: string;
  actorId: string;
  actorName: string;
}

Example:

// Command - give 50 gold pieces
{
  "id": "1",
  "type": "add-item-to-actor",
  "params": {
    "actorId": "abc123",
    "name": "Gold Coins",
    "type": "loot",
    "system": {
      "quantity": 50,
      "price": { "value": 1, "denomination": "gp" }
    }
  }
}

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "id": "item-new-001",
    "name": "Gold Coins",
    "type": "loot",
    "img": "icons/commodities/currency/coins-gold.png",
    "actorId": "abc123",
    "actorName": "Aragorn"
  }
}

add-item-from-compendium

Add an item from a compendium pack to an actor's inventory. Useful for giving standard SRD equipment, weapons, potions, etc.

Params:

interface AddItemFromCompendiumParams {
  actorId: string;
  packId: string;      // Compendium ID, e.g., "dnd5e.items"
  itemId: string;      // Item ID within compendium
  name?: string;       // Override item name
  quantity?: number;   // Override quantity
}

Result: ItemResult

Example:

// Command - give Healing Potion from SRD
{
  "id": "1",
  "type": "add-item-from-compendium",
  "params": {
    "actorId": "abc123",
    "packId": "dnd5e.items",
    "itemId": "potion-of-healing-id",
    "quantity": 3
  }
}

// Command - give custom-named weapon
{
  "id": "2",
  "type": "add-item-from-compendium",
  "params": {
    "actorId": "abc123",
    "packId": "dnd5e.items",
    "itemId": "longsword-id",
    "name": "Flame Tongue Longsword"
  }
}

update-actor-item

Update an existing item in an actor's inventory.

Params:

interface UpdateActorItemParams {
  actorId: string;
  itemId: string;
  name?: string;
  img?: string;
  system?: Partial<ItemSystemData>;  // Partial update
}

Result: ItemResult

Example:

// Command - update quantity (consume 2 potions)
{
  "id": "1",
  "type": "update-actor-item",
  "params": {
    "actorId": "abc123",
    "itemId": "potion-item-id",
    "system": { "quantity": 1 }
  }
}

// Command - equip item
{
  "id": "2",
  "type": "update-actor-item",
  "params": {
    "actorId": "abc123",
    "itemId": "armor-item-id",
    "system": { "equipped": true }
  }
}

delete-actor-item

Remove an item from an actor's inventory.

Params:

interface DeleteActorItemParams {
  actorId: string;
  itemId: string;
}

Result: DeleteResult

Example:

{ "id": "1", "type": "delete-actor-item", "params": { "actorId": "abc123", "itemId": "broken-sword-id" } }
{ "id": "1", "success": true, "data": { "deleted": true } }

Effect Management

get-actor-effects

Get all active effects on an actor.

Params:

interface GetActorEffectsParams {
  actorId: string;
  includeDisabled?: boolean;  // Include disabled effects (default: true)
}

Result:

interface ActorEffectsResult {
  actorId: string;
  actorName: string;
  effects: EffectSummary[];
  activeStatuses: string[];   // Currently active status IDs
}

interface EffectSummary {
  id: string;
  name: string;
  img: string;
  disabled: boolean;
  isTemporary: boolean;
  statuses: string[];
  origin: string | null;
  changes?: EffectChangeData[];
  duration?: EffectDurationData;
}

interface EffectChangeData {
  key: string;    // e.g., "system.attributes.ac.bonus"
  value: string;
  mode: number;   // See change modes below
}

interface EffectDurationData {
  seconds?: number;
  rounds?: number;
  turns?: number;
}

Change Modes:

Mode Name Description
0 CUSTOM Custom handling
1 MULTIPLY Multiply value
2 ADD Add to value
3 DOWNGRADE Use lower value
4 UPGRADE Use higher value
5 OVERRIDE Replace value

Example:

// Command
{ "id": "1", "type": "get-actor-effects", "params": { "actorId": "abc123" } }

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "actorId": "abc123",
    "actorName": "Aragorn",
    "effects": [
      {
        "id": "effect-001",
        "name": "Bless",
        "img": "icons/magic/holy/bless.png",
        "disabled": false,
        "isTemporary": true,
        "statuses": [],
        "origin": "Item.spell-123",
        "changes": [{ "key": "system.bonuses.abilities.save", "value": "1d4", "mode": 2 }],
        "duration": { "rounds": 10 }
      },
      {
        "id": "effect-002",
        "name": "Prone",
        "img": "icons/conditions/prone.png",
        "disabled": false,
        "isTemporary": false,
        "statuses": ["prone"],
        "origin": null
      }
    ],
    "activeStatuses": ["prone"]
  }
}

toggle-actor-status

Toggle a D&D 5e status condition on/off.

Params:

interface ToggleActorStatusParams {
  actorId: string;
  statusId: string;      // See available statuses below
  active?: boolean;      // Force active/inactive state
  overlay?: boolean;     // Show as large overlay on token
}

Available Status IDs:

Status Status Status
blinded frightened petrified
charmed grappled poisoned
concentrating incapacitated prone
dead invisible restrained
deafened paralyzed stunned
exhaustion unconscious

Result:

interface ToggleStatusResult {
  actorId: string;
  statusId: string;
  active: boolean;       // New state
  effectId?: string;     // Effect ID if created
}

Example:

// Command - apply stunned condition
{ "id": "1", "type": "toggle-actor-status", "params": { "actorId": "abc123", "statusId": "stunned", "active": true } }

// Response
{ "id": "1", "success": true, "data": { "actorId": "abc123", "statusId": "stunned", "active": true, "effectId": "effect-new-001" } }

// Command - remove stunned condition
{ "id": "2", "type": "toggle-actor-status", "params": { "actorId": "abc123", "statusId": "stunned", "active": false } }

// Response
{ "id": "2", "success": true, "data": { "actorId": "abc123", "statusId": "stunned", "active": false } }

add-actor-effect

Create a custom ActiveEffect on an actor.

Params:

interface AddActorEffectParams {
  actorId: string;
  name: string;
  img?: string;
  disabled?: boolean;
  origin?: string;              // Source reference, e.g., "Item.spell-id"
  statuses?: string[];          // Associated status IDs
  changes?: EffectChangeData[];
  duration?: EffectDurationData;
}

Result:

interface AddEffectResult {
  actorId: string;
  effectId: string;
  name: string;
}

Example:

// Command - add Shield of Faith effect (+2 AC for 10 minutes)
{
  "id": "1",
  "type": "add-actor-effect",
  "params": {
    "actorId": "abc123",
    "name": "Shield of Faith",
    "img": "icons/magic/defensive/shield.png",
    "changes": [{ "key": "system.attributes.ac.bonus", "value": "2", "mode": 2 }],
    "duration": { "seconds": 600 }
  }
}

// Response
{ "id": "1", "success": true, "data": { "actorId": "abc123", "effectId": "effect-new-002", "name": "Shield of Faith" } }

remove-actor-effect

Remove an effect from an actor.

Params:

interface RemoveActorEffectParams {
  actorId: string;
  effectId: string;
}

Result:

interface RemoveEffectResult {
  actorId: string;
  effectId: string;
  removed: boolean;
}

Example:

{ "id": "1", "type": "remove-actor-effect", "params": { "actorId": "abc123", "effectId": "effect-001" } }
{ "id": "1", "success": true, "data": { "actorId": "abc123", "effectId": "effect-001", "removed": true } }

update-actor-effect

Update an existing effect's properties.

Params:

interface UpdateActorEffectParams {
  actorId: string;
  effectId: string;
  name?: string;
  img?: string;
  disabled?: boolean;
  changes?: EffectChangeData[];
  duration?: EffectDurationData;
}

Result:

interface UpdateEffectResult {
  actorId: string;
  effectId: string;
  name: string;
}

Example:

// Command - disable an effect
{ "id": "1", "type": "update-actor-effect", "params": { "actorId": "abc123", "effectId": "effect-001", "disabled": true } }

// Response
{ "id": "1", "success": true, "data": { "actorId": "abc123", "effectId": "effect-001", "name": "Bless" } }

Compendium Access

get-compendiums

Get a list of all available compendium packs.

Params:

// No parameters required
interface GetCompendiumsParams {}

Result:

type GetCompendiumsResult = CompendiumMetadata[];

interface CompendiumMetadata {
  id: string;              // e.g., "dnd5e.monsters"
  label: string;           // e.g., "Monsters (SRD)"
  type: string;            // "Actor", "Item", "JournalEntry", "Scene", etc.
  system: string;          // e.g., "dnd5e"
  packageName: string;     // e.g., "dnd5e"
  documentCount: number;   // Number of entries
}

Example:

// Command
{ "id": "1", "type": "get-compendiums", "params": {} }

// Response
{
  "id": "1",
  "success": true,
  "data": [
    { "id": "dnd5e.monsters", "label": "Monsters (SRD)", "type": "Actor", "system": "dnd5e", "packageName": "dnd5e", "documentCount": 325 },
    { "id": "dnd5e.items", "label": "Items (SRD)", "type": "Item", "system": "dnd5e", "packageName": "dnd5e", "documentCount": 680 },
    { "id": "dnd5e.spells", "label": "Spells (SRD)", "type": "Item", "system": "dnd5e", "packageName": "dnd5e", "documentCount": 319 }
  ]
}

get-compendium

Get full contents of a compendium pack, including all documents with their data.

Params:

interface GetCompendiumParams {
  packId: string;          // Compendium ID, e.g., "dnd5e.monsters"
}

Result:

interface CompendiumData {
  id: string;
  label: string;
  type: string;
  system: string;
  documentCount: number;
  documents: CompendiumDocument[];
}

interface CompendiumDocument {
  id: string;
  uuid: string;
  name: string;
  type: string;
  img: string;
  system?: Record<string, unknown>;
  items?: ItemData[];          // For Actor documents
  pages?: JournalPageData[];   // For JournalEntry documents
}

Example:

// Command
{ "id": "1", "type": "get-compendium", "params": { "packId": "dnd5e.monsters" } }

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "id": "dnd5e.monsters",
    "label": "Monsters (SRD)",
    "type": "Actor",
    "system": "dnd5e",
    "documentCount": 325,
    "documents": [
      {
        "id": "goblin-001",
        "uuid": "Compendium.dnd5e.monsters.goblin-001",
        "name": "Goblin",
        "type": "npc",
        "img": "tokens/goblin.png",
        "system": { "attributes": { "hp": { "value": 7, "max": 7 } } }
      }
    ]
  }
}

Roll Tables

list-roll-tables

Get a summary list of all roll tables in the world.

Params:

// No parameters required
interface ListRollTablesParams {}

Result:

type ListRollTablesResult = RollTableSummary[];

interface RollTableSummary {
  id: string;
  name: string;
  img: string;
  description: string;
  formula: string;           // e.g., "1d20", "1d100"
  replacement: boolean;      // Draw with replacement
  totalResults: number;      // Total number of entries
  drawnResults: number;      // Number already drawn (when replacement: false)
}

Example:

// Command
{ "id": "1", "type": "list-roll-tables", "params": {} }

// Response
{
  "id": "1",
  "success": true,
  "data": [
    {
      "id": "table-1",
      "name": "Random Encounters",
      "img": "icons/svg/d20.svg",
      "description": "Forest encounter table",
      "formula": "1d20",
      "replacement": true,
      "totalResults": 20,
      "drawnResults": 0
    }
  ]
}

get-roll-table

Get full details of a roll table including all result entries.

Params:

interface GetRollTableParams {
  tableId: string;
}

Result:

interface RollTableResult {
  id: string;
  name: string;
  img: string;
  description: string;
  formula: string;
  replacement: boolean;
  displayRoll: boolean;      // Show roll in chat
  results: TableResultData[];
}

interface TableResultData {
  id: string;
  type: number;              // 0 = text, 1 = document, 2 = compendium
  text: string;
  img: string;
  range: [number, number];   // [min, max] roll range
  weight: number;
  drawn: boolean;            // Already drawn (for no-replacement tables)
  documentCollection: string | null;  // For document/compendium references
  documentId: string | null;
}

Example:

// Command
{ "id": "1", "type": "get-roll-table", "params": { "tableId": "table-1" } }

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "id": "table-1",
    "name": "Random Encounters",
    "img": "icons/svg/d20.svg",
    "description": "Forest encounter table",
    "formula": "1d20",
    "replacement": true,
    "displayRoll": true,
    "results": [
      { "id": "res-1", "type": 0, "text": "2d4 Wolves", "img": "", "range": [1, 5], "weight": 1, "drawn": false, "documentCollection": null, "documentId": null },
      { "id": "res-2", "type": 0, "text": "1 Owlbear", "img": "", "range": [6, 10], "weight": 1, "drawn": false, "documentCollection": null, "documentId": null }
    ]
  }
}

roll-on-table

Roll on a table and get the result. Optionally displays the roll in Foundry chat.

Params:

interface RollOnTableParams {
  tableId: string;
  displayChat?: boolean;     // Show in chat (default: true)
}

Result:

interface RollOnTableResult {
  tableId: string;
  tableName: string;
  roll: {
    formula: string;
    total: number;
  };
  results: TableResultData[];  // Matched result entries
}

Example:

// Command
{ "id": "1", "type": "roll-on-table", "params": { "tableId": "table-1" } }

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "tableId": "table-1",
    "tableName": "Random Encounters",
    "roll": { "formula": "1d20", "total": 7 },
    "results": [
      { "id": "res-2", "type": 0, "text": "1 Owlbear", "img": "", "range": [6, 10], "weight": 1, "drawn": false, "documentCollection": null, "documentId": null }
    ]
  }
}

reset-table

Reset a roll table, marking all results as not drawn. Useful for tables with replacement: false.

Params:

interface ResetTableParams {
  tableId: string;
}

Result:

interface ResetTableResult {
  tableId: string;
  tableName: string;
  resetCount: number;        // Number of results reset
}

Example:

// Command
{ "id": "1", "type": "reset-table", "params": { "tableId": "table-1" } }

// Response
{ "id": "1", "success": true, "data": { "tableId": "table-1", "tableName": "Random Encounters", "resetCount": 20 } }

create-roll-table

Create a new roll table with optional pre-defined results.

Params:

interface CreateRollTableParams {
  name: string;
  formula?: string;          // Default: "1d20"
  replacement?: boolean;     // Default: true
  displayRoll?: boolean;     // Default: true
  description?: string;
  img?: string;
  folder?: string;           // Folder ID
  results?: CreateTableResultData[];
}

interface CreateTableResultData {
  text: string;
  range: [number, number];   // [min, max]
  weight?: number;           // Default: 1
  type?: number;             // 0 = text (default), 1 = document, 2 = compendium
  documentCollection?: string;
  documentId?: string;
  img?: string;
}

Result: RollTableResult

Example:

// Command
{
  "id": "1",
  "type": "create-roll-table",
  "params": {
    "name": "Treasure Hoard",
    "formula": "1d6",
    "description": "Loot from dragon's hoard",
    "results": [
      { "text": "100 gold pieces", "range": [1, 2] },
      { "text": "Potion of Healing", "range": [3, 4] },
      { "text": "Magic Sword +1", "range": [5, 5] },
      { "text": "Diamond worth 500gp", "range": [6, 6] }
    ]
  }
}

update-roll-table

Update roll table properties (does not modify individual results).

Params:

interface UpdateRollTableParams {
  tableId: string;
  name?: string;
  formula?: string;
  replacement?: boolean;
  displayRoll?: boolean;
  description?: string;
  img?: string;
}

Result: RollTableResult

Example:

// Command
{ "id": "1", "type": "update-roll-table", "params": { "tableId": "table-1", "name": "Updated Encounters", "formula": "1d100" } }

delete-roll-table

Delete a roll table from the world.

Params:

interface DeleteRollTableParams {
  tableId: string;
}

Result: DeleteResult

Example:

{ "id": "1", "type": "delete-roll-table", "params": { "tableId": "table-1" } }
{ "id": "1", "success": true, "data": { "deleted": true } }

Door Management

set-door-state

Set the state of a door on a scene wall. The wall must be a door (door type 1 or 2).

Params:

interface SetDoorStateParams {
  sceneId?: string;          // Defaults to active scene
  wallId: string;            // Wall ID (must be a door)
  state: number;             // 0 = closed, 1 = open, 2 = locked
}

Result:

interface SetDoorStateResult {
  wallId: string;
  door: number;              // Door type (1 = door, 2 = secret door)
  previousState: number;     // State before the change
  newState: number;          // State after the change
}

Example:

// Command - open a door
{ "id": "1", "type": "set-door-state", "params": { "wallId": "wall-door-1", "state": 1 } }

// Response
{
  "id": "1",
  "success": true,
  "data": {
    "wallId": "wall-door-1",
    "door": 1,
    "previousState": 0,
    "newState": 1
  }
}

// Command - lock a door
{ "id": "2", "type": "set-door-state", "params": { "wallId": "wall-door-1", "state": 2 } }

// Response
{ "id": "2", "success": true, "data": { "wallId": "wall-door-1", "door": 1, "previousState": 1, "newState": 2 } }

Error Handling

On error, response includes success: false and error message:

{
  "id": "123",
  "success": false,
  "error": "Actor not found: invalid-id"
}

Common errors:

  • Actor/Item/Scene/Combat not found
  • Invalid parameters
  • Combat not started (for turn navigation)
  • Permission denied

Clone this wiki locally