Skip to main content

Roll

GET /rolls

Get recent rolls

Retrieves a list of up to 20 recent rolls made in the Foundry world.

Required scope: roll:read

Parameters

NameTypeRequiredSourceDescription
clientIdstringqueryClient ID for the Foundry world
limitnumberqueryOptional limit on the number of rolls to return (default is 20)
userIdstringquery, bodyFoundry user ID or username to scope permissions (omit for GM-level access)

Returns

array - An array of recent rolls with details

Try It Out

Code Examples

const baseUrl = 'http://localhost:3010';
const path = '/rolls';
const params = {
clientId: 'fvtt_099ad17ea199e7e3',
limit: '20'
};
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": "rolls-result",
"requestId": "rolls_1778896424608",
"data": [
0: {
"id": "manual_1778896424102_l0jfemg94sh",
"messageId": "manual_1778896424102_l0jfemg94sh",
"user": null,
"speaker": {},
"flavor": "Test Roll",
"rollTotal": 16,
"formula": "2d20kh",
"isCritical": false,
"isFumble": false,
"dice": [ 1 item ],
"timestamp": 1778896424102
},
1: {
"id": "manual_1778896413186_z1jrn5ycr6",
"messageId": null,
"user": null,
"speaker": {},
"flavor": "",
"rollTotal": 11,
"formula": "1d20",
"isCritical": false,
"isFumble": false,
"dice": [ 1 item ],
"timestamp": 1778896413186
}
]
}

GET /lastroll

Get the last roll

Retrieves the most recent roll made in the Foundry world.

Required scope: roll:read

Parameters

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

Returns

object - The most recent roll with details

Try It Out

Code Examples

const baseUrl = 'http://localhost:3010';
const path = '/lastroll';
const params = {
clientId: 'fvtt_099ad17ea199e7e3'
};
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": "last-roll-result",
"requestId": "last-roll_1778896424612",
"data": {
"id": "manual_1778896424102_l0jfemg94sh",
"messageId": "manual_1778896424102_l0jfemg94sh",
"user": null,
"speaker": {},
"flavor": "Test Roll",
"rollTotal": 16,
"formula": "2d20kh",
"isCritical": false,
"isFumble": false,
"dice": [
0: { 2 keys }
],
"timestamp": 1778896424102
}
}

POST /roll

Make a roll

Executes a roll with the specified formula.

Required scope: roll:execute

Parameters

NameTypeRequiredSourceDescription
formulastringbodyThe roll formula to evaluate (e.g., "1d20 + 5")
clientIdstringqueryClient ID for the Foundry world
flavorstringbodyOptional flavor text for the roll
createChatMessagebooleanbodyWhether to create a chat message for the roll
speakerstringbodyThe speaker for the roll
whisperarraybodyUsers to whisper the roll result to
userIdstringquery, bodyFoundry user ID or username to scope permissions (omit for GM-level access)

Returns

object - Result of the roll operation

Try It Out

Code Examples

const baseUrl = 'http://localhost:3010';
const path = '/roll';
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({
"formula": "2d20kh",
"flavor": "Test Roll",
"createChatMessage": true
})
});
const data = await response.json();
console.log(data);

Response

Status: 200

{
"type": "roll-result",
"requestId": "roll_1778896424096",
"success": true,
"data": {
"id": "manual_1778896424102_l0jfemg94sh",
"chatMessageCreated": true,
"roll": {
"formula": "2d20kh",
"total": 16,
"isCritical": false,
"isFumble": false,
"dice": [ 1 item ],
"timestamp": 1778896424102
}
}
}

GET /rolls/subscribe

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

Opens a persistent SSE connection that streams roll events as they occur.

Required scope: events:subscribe

Parameters

NameTypeRequiredSourceDescription
clientIdstringqueryClient ID for the Foundry world
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}/rolls/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 }
})
});

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

eventSource.addEventListener('roll', (event) => {
const roll = JSON.parse(event.data);
const dice = roll.dice?.map(d =>
`${d.results.map(r => `${r.result}${r.active ? '' : '(dropped)'}`).join(', ')} (d${d.faces})`
).join(' + ') || '';
console.log(`[${roll.user?.name}] ${roll.formula} = ${roll.rollTotal}${roll.isCritical ? ' CRITICAL!' : ''}${roll.isFumble ? ' FUMBLE!' : ''}`);
if (roll.flavor) console.log(` Flavor: ${roll.flavor}`);
if (dice) console.log(` Dice: ${dice}`);
});

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

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

Response

Status: 200

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