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
contentstring✓bodyThe 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
messageIdstring✓paramsID 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"
}
}