Skip to main content

Chat

GET /chat

Get chat messages

Retrieves chat messages from the Foundry world with optional pagination and filtering.

Required scope: chat:read

Parameters

NameTypeRequiredSourceDescription
clientIdstringqueryClient ID for the Foundry world
limitnumberqueryMaximum number of messages to return (default: 10)
offsetnumberqueryNumber of messages to skip for pagination
userIdstringquery, bodyFoundry user ID or username to scope permissions (omit for GM-level access)
chatTypenumberqueryFoundry chat message type (0=OOC, 1=IC, 2=Emote, 3=Whisper, 4=Roll). Named chatType to avoid collision with WS message type field.
speakerstringqueryFilter messages by speaker name or actor ID

Returns

object - Paginated list of chat messages

Try It Out

Code Examples

const baseUrl = 'http://localhost:3010';
const path = '/chat';
const params = {
clientId: 'fvtt_099ad17ea199e7e3',
limit: '10'
};
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);

Response

Status: 200

{
"type": "chat-messages-result",
"requestId": "chat-messages_1778896437015",
"success": true,
"data": {
"messages": [
0: { 12 keys },
1: { 12 keys },
2: { 12 keys },
3: { 12 keys },
4: { 12 keys },
5: { 12 keys },
6: { 12 keys },
7: { 12 keys }
],
"total": 8,
"offset": 0,
"limit": 10
}
}

POST /chat

Send a chat message

Creates a new chat message in the Foundry world.

Required scope: chat:write

Parameters

NameTypeRequiredSourceDescription
contentstringbodyThe message content (supports HTML)
clientIdstringqueryClient ID for the Foundry world
whisperarraybodyArray of user IDs to whisper the message to
speakerstringbodyActor ID to use as the message speaker
aliasstringbodyDisplay name alias for the speaker
chatTypenumberbodyFoundry chat message type (0=OOC, 1=IC, 2=Emote, 3=Whisper, 4=Roll). Named chatType to avoid collision with WS message type field.
flavorstringbodyFlavor text displayed above the message content
userIdstringquery, bodyFoundry user ID or username to scope permissions (omit for GM-level access)

Returns

object - The created chat message

Try It Out

Code Examples

const baseUrl = 'http://localhost:3010';
const path = '/chat';
const params = {
clientId: 'fvtt_099ad17ea199e7e3'
};
const queryString = new URLSearchParams(params).toString();
const url = `${baseUrl}${path}?${queryString}`;

const response = await fetch(url, {
method: 'POST',
headers: {
'x-api-key': 'your-api-key-here',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"content": "Hello from the REST API test suite!",
"flavor": "Test Message"
})
});
const data = await response.json();
console.log(data);

Response

Status: 200

{
"type": "chat-send-result",
"requestId": "chat-send_1778896436998",
"success": true,
"data": {
"id": "jeEuQHAjC0zWCCbJ",
"uuid": "ChatMessage.jeEuQHAjC0zWCCbJ",
"content": "Hello from the REST API test suite!",
"speaker": {
"scene": null,
"actor": null,
"token": null
},
"timestamp": 1778896436998,
"whisper": [],
"type": "base",
"author": {
"id": "r6bXhB7k9cXa3cif",
"name": "tester"
},
"flavor": "Test Message",
"isRoll": false,
"rolls": [],
"flags": {}
}
}

DELETE /chat/:messageId

Delete a specific chat message

Deletes a chat message by its ID. Only the message author or a GM can delete messages.

Required scope: chat:write

Parameters

NameTypeRequiredSourceDescription
messageIdstringparamsID of the chat message to delete
clientIdstringqueryClient ID for the Foundry world
userIdstringquery, bodyFoundry user ID or username to scope permissions (omit for GM-level access)

Returns

object - Success confirmation

Try It Out

Code Examples

const baseUrl = 'http://localhost:3010';
const path = '/chat/jeEuQHAjC0zWCCbJ';
const params = {
clientId: 'fvtt_099ad17ea199e7e3'
};
const queryString = new URLSearchParams(params).toString();
const url = `${baseUrl}${path}?${queryString}`;

const response = await fetch(url, {
method: 'DELETE',
headers: {
'x-api-key': 'your-api-key-here'
}
});
const data = await response.json();
console.log(data);

Response

Status: 200

{
"type": "chat-delete-result",
"requestId": "chat-delete_1778896437023",
"success": true,
"data": {
"messageId": "jeEuQHAjC0zWCCbJ"
}
}

DELETE /chat

Clear all chat messages

Flushes all chat message history. Only GMs can perform this action.

Required scope: chat:write

Parameters

NameTypeRequiredSourceDescription
clientIdstringqueryClient ID for the Foundry world
userIdstringquery, bodyFoundry user ID or username to scope permissions (omit for GM-level access)

Returns

object - Success confirmation

Try It Out

Code Examples

const baseUrl = 'http://localhost:3010';
const path = '/chat';
const params = {
clientId: 'fvtt_099ad17ea199e7e3'
};
const queryString = new URLSearchParams(params).toString();
const url = `${baseUrl}${path}?${queryString}`;

const response = await fetch(url, {
method: 'DELETE',
headers: {
'x-api-key': 'your-api-key-here'
}
});
const data = await response.json();
console.log(data);

Response

Status: 200

{
"type": "chat-flush-result",
"requestId": "chat-flush_1778896437041",
"success": true,
"data": {
"message": "All chat messages have been deleted"
}
}

GET /chat/subscribe

Subscribe to real-time chat events via Server-Sent Events (SSE)

Opens a persistent SSE connection that streams chat events (create, update, delete) as they occur in the Foundry world.

Required scope: events:subscribe

Parameters

NameTypeRequiredSourceDescription
clientIdstringqueryClient ID for the Foundry world
speakerstringqueryFilter events by speaker name or actor ID
typenumberqueryFilter events by chat message type (0=OOC, 1=IC, 2=Emote, 3=Whisper, 4=Roll)
whisperOnlybooleanqueryOnly receive whispered messages
userIdstringqueryFoundry user ID or username to scope permissions (omit for GM-level access)

Returns

SSE stream - SSE event stream

Try It Out

Code Examples

const { EventSource } = require('eventsource'); // npm install eventsource

const baseUrl = 'http://localhost:3010';
const apiKey = 'your-api-key-here';
const url = `${baseUrl}/chat/subscribe?clientId=your-client-id`;

// eventsource v4 uses a custom fetch function to inject headers
const eventSource = new EventSource(url, {
fetch: (input, init) => fetch(input, {
...init,
headers: { ...init?.headers, 'x-api-key': apiKey }
})
});

function formatMessage(prefix, message) {
const speaker = message.author?.name || message.speaker?.alias || '?';
console.log(`[${prefix}] ${speaker}: ${message.content}`);
if (message.flavor) console.log(` Flavor: ${message.flavor}`);
if (message.isRoll && message.rolls?.length > 0) {
for (const roll of message.rolls) {
const dice = roll.dice?.map(d =>
`${d.results.map(r => `${r.result}${r.active ? '' : '(dropped)'}`).join(', ')} (d${d.faces})`
).join(' + ') || '';
console.log(` Roll: ${roll.formula} = ${roll.total}${roll.isCritical ? ' CRITICAL!' : ''}${roll.isFumble ? ' FUMBLE!' : ''}`);
if (dice) console.log(` Dice: ${dice}`);
}
}
}

eventSource.addEventListener('connected', (event) => {
const data = JSON.parse(event.data);
console.log('Connected:', data.clientId);
});

eventSource.addEventListener('chat-create', (event) => {
const message = JSON.parse(event.data);
formatMessage('new', message);
});

eventSource.addEventListener('chat-update', (event) => {
const message = JSON.parse(event.data);
formatMessage('updated', message);
});

eventSource.addEventListener('chat-delete', (event) => {
const data = JSON.parse(event.data);
console.log('Message deleted:', JSON.stringify(data));
});

eventSource.onerror = (error) => {
console.error('SSE error:', error);
};

// To disconnect later:
// eventSource.close();

Response

Status: 200

{
"event": "connected",
"data": {
"clientId": "fvtt_099ad17ea199e7e3"
}
}