-
-
Notifications
You must be signed in to change notification settings - Fork 3
WebSocket API
The module connects to your server as a WebSocket client. Your server sends commands, Foundry executes them and returns results.
- Foundry connects to:
ws://your-server:port/ws - Protocol: JSON messages
- Auto-reconnect: Configurable interval and max attempts
interface Command {
id: string; // Unique identifier for correlation
type: CommandType;
params: object;
}interface CommandResponse {
id: string; // Same as command ID
success: boolean;
data?: object; // Result on success
error?: string; // Error message on failure
}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 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 D&D 5e saving throw.
Params:
interface RollSaveParams {
actorId: string;
ability: AbilityKey; // "str", "dex", "con", "int", "wis", "cha"
showInChat?: boolean;
}Roll D&D 5e ability check.
Params:
interface RollAbilityParams {
actorId: string;
ability: AbilityKey;
showInChat?: boolean;
}Roll attack with weapon/spell.
Params:
interface RollAttackParams {
actorId: string;
itemId: string; // Weapon/spell item ID
advantage?: boolean;
disadvantage?: boolean;
showInChat?: boolean;
}Roll damage for weapon/spell.
Params:
interface RollDamageParams {
actorId: string;
itemId: string;
critical?: boolean; // Double dice
showInChat?: boolean;
}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 }
]
}
}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 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": {} }
]
}
}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-actorsfor 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 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
}
}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 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 from the world.
Params:
interface DeleteActorParams {
actorId: string;
}Result: DeleteResult
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"
}
}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 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 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 } }Delete all messages from the chat log.
Params:
// No parameters requiredResult:
interface ClearChatResult {
deletedCount: number;
}Example:
// Command
{ "id": "1", "type": "clear-chat", "params": {} }
// Response
{ "id": "1", "success": true, "data": { "deletedCount": 142 } }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" } }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 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 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 properties.
Params:
interface UpdateJournalParams {
journalId: string;
name?: string;
folder?: string;
}Delete journal entry.
Params:
interface DeleteJournalParams {
journalId: string;
}Result:
interface DeleteResult {
deleted: boolean;
}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 page content.
Params:
interface UpdateJournalPageParams {
journalId: string;
pageId: string;
name?: string;
content?: string;
src?: string; // Source URL for image/video/pdf pages
}Remove page from journal.
Params:
interface DeleteJournalPageParams {
journalId: string;
pageId: string;
}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"]
}
}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 actor to combat.
Params:
interface AddCombatantParams {
actorId: string;
combatId?: string; // Defaults to active combat
tokenId?: string;
initiative?: number; // Pre-set initiative
hidden?: boolean;
}Remove from combat.
Params:
interface RemoveCombatantParams {
combatantId: string;
combatId?: string;
}Begin combat (sets round to 1).
Params:
interface CombatIdParams {
combatId?: string;
}End and delete combat. Shows confirmation dialog in Foundry VTT v13.
Params: CombatIdParams
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" } }Navigate turn order.
Params: CombatIdParams
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 current combat state.
Params: CombatIdParams
Result: CombatResult
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) ..."
}
}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;
}>;
}Manually set initiative value.
Params:
interface SetInitiativeParams {
combatantId: string;
initiative: number;
combatId?: string;
}Roll initiative for all combatants.
Params:
interface RollAllInitiativeParams {
combatId?: string;
formula?: string;
npcsOnly?: boolean; // Roll only for NPCs
}Update combatant properties.
Params:
interface UpdateCombatantParams {
combatantId: string;
combatId?: string;
initiative?: number;
defeated?: boolean;
hidden?: boolean;
}Mark combatant as defeated.
Params:
interface SetCombatantDefeatedParams {
combatantId: string;
defeated: boolean;
combatId?: string;
}Toggle hidden status.
Params:
interface ToggleCombatantVisibilityParams {
combatantId: string;
combatId?: string;
}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
}Remove token from scene.
Params:
interface DeleteTokenParams {
tokenId: string;
sceneId?: string;
}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 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 all tokens from scene.
Params:
interface GetSceneTokensParams {
sceneId?: string; // Defaults to active scene
}Result:
interface SceneTokensResult {
sceneId: string;
sceneName: string;
tokens: TokenResult[];
}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 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" }
]
}
}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 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
}
}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 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 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/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 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"
}
}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 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 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 }
}
}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 } }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 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 } }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 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 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" } }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 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 } } }
}
]
}
}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 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 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 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 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 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 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 } }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 } }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