Foundry VTT REST API Relay

website·Indexed 30 days ago

https://foundryrestapi.com/docs

A relay server and Foundry VTT module that provides a REST and WebSocket API for bidirectional communication with Foundry Virtual Tabletop. It includes endpoints for managing entities, scenes, actors, chat, macros, and rolls, as well as support for scoped API keys and real-time event subscriptions.

Tokens
47.4K
Snippets
259
Records
328
Agent score
50%

What's inside Foundry REST API

  1. Overview of Foundry REST API Architecture

    The Foundry REST API is composed of two interconnected components that enable external applications to interact with Foundry VTT:

    1. Relay Server (foundryvtt-rest-api-relay): A Go application that provides HTTP REST endpoints for external clients, manages WebSocket connections to Foundry, handles authentication/session management, and routes requests.
    2. Foundry Module (foundryvtt-rest-api): A TypeScript module running inside Foundry VTT as a GM-only module. It connects to the relay server via WebSocket, receives requests, executes Foundry API calls, and returns the results.
  2. Retrieve detailed D&D 5e actor information

    Use the GET /dnd5e/get-actor-details endpoint to retrieve comprehensive details about a specific D&D 5e actor, such as stats, inventory, spells, and features. This endpoint requires the dnd5e scope. Permissions can be scoped to a specific user via userId; omit this for GM-level access.
    const baseUrl = 'http://localhost:3011';
    const path = '/dnd5e/get-actor-details';
    const params = {
      clientId: 'qsl-integration-test',
      actorUuid: 'Actor.V5OF1QXHjaIy6iO8',
      details: '["resources","items","features","spells"]'
    };
    const queryString = new URLSearchParams(params).toString();
    const url = `${baseUrl}${path}?${queryString}`;
    
    const response = await fetch(url, {
      method: 'GET',
      headers: {
        'x-api-key': 'your-api-key-here'
      }
    });
    const data = await response.json();
    console.log(data);
  3. Understand the Foundry REST API test suite structure

    The test suite is organized into integration tests and helper utilities. Integration tests cover specific API domains (sessions, clients, entities, auth, scenes, canvas, etc.) and are executed in a strict sequence to ensure dependencies (like session creation and entity setup) are met before functional tests run. Cleanup tests run last to restore the environment.
    tests/
    ├── integration/        # API integration tests (e.g., session-endpoints.test.ts, entity-endpoints.test.ts)
    ├── helpers/             # Test utilities (e.g., apiRequest.ts, multiVersion.ts, testEntities.ts)
    ├── setup.ts             # Jest setup (loads .env.test)
    └── globalTeardown.ts    # Final cleanup
  4. Understand Foundry VTT WebSocket Search Response Format

    When performing a search via the Foundry VTT WebSocket API, the server returns a JSON response containing the client ID, the original query, a unique request ID, and an array of results. Each result object provides detailed metadata about the matched entity, including its document type, unique ID, UUID, and whether it is a WorldEntity or a CompendiumEntity.
    {
      "clientId": "qsl-integration-test",
      "query": "test",
      "requestId": "test_1782956933625_v13y2n",
      "results": [
        {
          "documentType": "Scene",
          "folder": null,
          "formattedMatch": "<strong>test</strong>",
          "icon": "",
          "id": "UTjLwXV2Zl26XPRl",
          "journalLink": "@UUID[Scene.UTjLwXV2Zl26XPRl]{test}",
          "name": "test",
          "package": null,
          "packageName": null,
          "resultType": "WorldEntity",
          "subType": "",
          "tagline": "Scenes Directory",
          "uuid": "Scene.UTjLwXV2Zl26XPRl"
        },
        {
          "documentType": "Actor",
          "folder": null,
          "formattedMatch": "Updated <strong>Test</strong> Actor",
          "icon": "systems/dnd5e/tokens/heroes/MonkStaff.webp",
          "id": "V5OF1QXHjaIy6iO8",
          "journalLink": "@UUID[Actor.V5OF1QXHjaIy6iO8]{Updated Test Actor}",
          "name": "Updated Test Actor",
          "package": null,
          "packageName": null,
          "resultType": "WorldEntity",
          "subType": "character",
          "tagline": "Actors Directory",
          "uuid": "Actor.V5OF1QXHjaIy6iO8"
        },
        {
          "documentType": "Item",
          "folder": null,
          "formattedMatch": "Adamantine Breastplate",
          "icon": "icons/equipment/chest/breastplate-collared-steel-grey.webp",
          "id": "DevmObXWP9MfwE2c",
          "journalLink": "@UUID[Compendium.dnd5e.items.Item.DevmObXWP9MfwE2c]{Adamantine Breastplate}",
          "name": "Adamantine Breastplate",
          "package": "dnd5e.items",
          "packageName": "Items (SRD)",
          "resultType": "CompendiumEntity",
          "subType": "equipment",
          "tagline": "Items (SRD)",
          "uuid": "Compendium.dnd5e.items.Item.DevmObXWP9MfwE2c"
        }
      ]
    }
  5. FoundryVTT REST API Resource Groups Overview

    The FoundryVTT REST API Relay server organizes its functionality into the following resource groups:

    • Auth: Registration, login, API key, and connection token management.
    • Canvas: Manipulation of embedded documents (tokens, walls, lights).
    • Chat: Sending, retrieving, and subscribing to chat messages.
    • Clients: Listing connected Foundry VTT worlds.
    • DnD5e: D&D 5th Edition specific endpoints.
    • Effects: Managing active effects on actors and tokens.
    • Encounter: Combat encounter management.
    • Entity: General manipulation of actors and items.
    • Events: Subscribing to real-time Foundry hook events via SSE.
    • File System: File management operations.
    • Macro: Executing and managing macros.
    • Playlist: Controlling playlists and audio tracks.
    • Roll: Performing dice rolls and subscribing to roll events.
    • Scene: Creating, updating, deleting, and switching scenes.
    • Search: Searching the Foundry database.
    • Session: Managing headless Foundry sessions.
    • Sheet: Interacting with character sheets.
    • Structure: Retrieving world structure information.
    • User: Listing and managing Foundry VTT users.
    • Utility: Miscellaneous utility endpoints.
    • WebSocket: Bidirectional real-time communication.
  6. Choose the correct Foundry REST API credential

    The Foundry REST API uses different credentials based on the client type and trust boundary:

    • Scoped API key: Used by external applications (Discord bots, Obsidian plugins, custom scripts) or for manual API testing. Sent via the x-api-key HTTP header.
    • Connection token: Used exclusively by the Foundry REST API module to connect to the relay's WebSocket. It cannot be used for HTTP API calls.
    • Dashboard session: Used for managing the account via the web dashboard; managed automatically by the browser via email/password login.
  7. Understand the FoundryVTT REST API Relay architecture

    The FoundryVTT REST API Relay enables external interactions with a Foundry Virtual Tabletop instance via a RESTful API. The system architecture consists of two primary components:

    1. The Relay Server: A Go application (self-hosted or public) that acts as a bridge. It manages WebSocket connections from Foundry VTT instances and exposes a secure HTTP/WebSocket API for external applications.
    2. The Foundry VTT Module: A module installed within Foundry VTT. It establishes a WebSocket connection to the relay server, authenticates using a per-browser connection token, and executes API commands within the active world.
  8. Target a specific Foundry world using clientId

    To interact with a specific world, include the clientId as a query parameter in your API requests.

    Auto-resolution: You can omit the clientId if:

    1. Only one client is currently online.
    2. Your API key is bound to a specific list of clients, and only one of those is online (or the key is bound to exactly one client).

    If multiple clients are online and no clientId is provided (and the key is not scoped to a single client), the API will return a 400 error listing the available clients.

    # Explicitly targeting a client
    curl -X GET "http://localhost:3010/structure?clientId=fvtt_3a9f1c2e4b7d8e0f&types=Actor" \
      -H "x-api-key: YOUR_API_KEY_HERE"
    
    # Using auto-resolution (works if only one client is online/bound)
    curl -X GET "http://localhost:3010/structure?types=Actor" \
      -H "x-api-key: YOUR_API_KEY_HERE"
  9. Implement cross-world communication in Foundry modules

    To interact with other Foundry worlds (e.g., syncing entities, folders, or users), modules must use the WebSocket tunnel provided by the relay via module.api.remoteRequest. Modules should never store HTTP API credentials, as these are broadcast to all connected clients and lack per-action gating. Cross-world authority is managed by the relay using per-token allowed-targets and per-token scopes.
  10. Deploy Foundry REST API Relay using Docker Compose

    The repository provides two primary Docker Compose configurations: docker-compose.local.yml for a simple SQLite setup (recommended for self-hosting) and docker-compose.postgres.yml for Postgres and optional Redis (recommended for horizontal scaling).
    # docker-compose.local.yml (self-hosted, SQLite)
    services:
      relay:
        image: threehats/foundryvtt-rest-api-relay:latest
        container_name: foundryvtt-rest-api-relay
        env_file: .env
        environment:
          - PORT=3010
          - DB_TYPE=sqlite
          - APP_ENV=production
        volumes:
          - ./data:/app/data
        ports:
          - "3010:3010"
        restart: unless-stopped

    Start the container:

    docker compose -f docker-compose.local.yml up -d

  11. Obtain a free domain via DuckDNS for Foundry VTT

    To provide a reachable address for your Foundry VTT server without purchasing a full domain, use DuckDNS:

    1. Log in to duckdns.org.
    2. Register your desired domain name.
    3. DuckDNS will automatically detect and associate your public IP address.

    Note: You do not need to set up a manual cron job for IP updates, as the Docker container used in this setup handles IP synchronization automatically.