Script Console API Reference for AI
This document is a complete API reference and code guide for writing scripts that run in Script Master's Script Console β an Atlassian Forge app that lets users run JavaScript automation scripts directly inside Jira, Confluence, or Bitbucket Cloud.
Use this document as context when asking an AI assistant (Claude, Gemini, ChatGPT, etc.) to generate scripts:
Here is the API reference: [link to this file]. Build a script for Script Console that [your task].
Execution Modelβ
Scripts run as async JavaScript functions inside a Forge Custom UI iframe. The Script Console wraps your code like this:
const result = await (async function(view, requestJira, showFlag, context) {
// YOUR SCRIPT CODE HERE
})(view, requestJira, showFlag, context);
Key implications:
- Top-level
awaitis supported β use it freely. - Use
returnto display a result in the output panel. - Use
console.log()for intermediate debug output. - Errors thrown by the script are caught and shown in the error panel.
- The script runs with the current user's permissions β no service account, no elevated access.
- No Node.js APIs (
fs,path, etc.) β browser/Forge globals only.
Available Globalsβ
Jiraβ
| Global | Type | Description |
|---|---|---|
requestJira | (path, options?) => Promise<Response> | Make authenticated calls to the Jira REST API |
view | Forge view object | Access context and UI lifecycle |
showFlag | (options) => Flag | Show a notification flag in the Jira UI |
context | FullContext object | Pre-fetched app context (user, cloud, extension info) |
fetch | Web fetch | Call any external HTTP endpoint |
console | Standard console | console.log(), console.error(), etc. |
Confluenceβ
| Global | Type | Description |
|---|---|---|
requestConfluence | (path, options?) => Promise<Response> | Make authenticated calls to the Confluence REST API |
view | Forge view object | Access context and UI lifecycle |
showFlag | (options) => Flag | Show a notification flag in the Confluence UI |
context | FullContext object | Pre-fetched app context |
fetch | Web fetch | Call any external HTTP endpoint |
console | Standard console | console.log(), console.error(), etc. |
Bitbucketβ
| Global | Type | Description |
|---|---|---|
requestBitbucket | (path, options?) => Promise<Response> | Make authenticated calls to the Bitbucket REST API |
view | Forge view object | Access context and UI lifecycle |
showFlag | (options) => Flag | Show a notification flag in the Bitbucket UI |
context | FullContext object | Pre-fetched app context |
fetch | Web fetch | Call any external HTTP endpoint |
console | Standard console | console.log(), console.error(), etc. |
API Referenceβ
requestJira(path, options?)β
Makes an authenticated HTTP request to the Jira Cloud REST API.
pathβ relative path starting with/rest/api/3/...optionsβ standardfetchRequestInitoptions (method, headers, body), minussignal- Returns β a standard
Responseobject
const response = await requestJira('/rest/api/3/myself', {
headers: { 'Accept': 'application/json' },
});
const data = await response.json();
return JSON.stringify(data);
requestConfluence(path, options?)β
Makes an authenticated HTTP request to the Confluence REST API.
pathβ relative path starting with/wiki/...optionsβ standardfetchoptions- Returns β a standard
Responseobject
const response = await requestConfluence('/wiki/rest/api/user/current', {
headers: { 'Accept': 'application/json' },
});
const data = await response.json();
return JSON.stringify(data);
requestBitbucket(path, options?)β
Makes an authenticated HTTP request to the Bitbucket REST API.
pathβ relative path starting with/2.0/...- Returns β a standard
Responseobject
const context = await view.getContext();
const response = await requestBitbucket(`/2.0/repositories/${context.workspaceId}`);
const data = await response.json();
return JSON.stringify(data);
view.getContext()β
Returns a FullContext object with information about the current user and environment.
const ctx = await view.getContext();
console.log(ctx.accountId); // current user's account ID
console.log(ctx.cloudId); // Atlassian site cloud ID
console.log(ctx.siteUrl); // e.g. "https://your-org.atlassian.net"
console.log(ctx.locale); // e.g. "en-US"
console.log(ctx.timezone); // e.g. "Europe/Berlin"
FullContext shape (relevant fields):
{
accountId?: string; // current user
cloudId?: string; // Atlassian cloud site ID
workspaceId?: string; // Bitbucket workspace ID
siteUrl: string; // base URL of the Atlassian site
locale: string;
timezone: string;
moduleKey: string;
environmentType: 'DEVELOPMENT' | 'STAGING' | 'PRODUCTION';
extension: ExtensionData; // Forge extension context
license?: {
active: boolean;
type: string;
// ...
};
}
Note: The
contextglobal is a pre-fetched snapshot ofview.getContext()β use it directly without an extra async call.
showFlag(options)β
Displays a notification flag in the Atlassian product UI.
const flag = showFlag({
id: 'my-flag', // unique ID (string or number)
title: 'Done!',
description: 'All issues updated successfully.',
type: 'success', // 'info' | 'success' | 'warning' | 'error'
isAutoDismiss: true,
actions: [
{
text: 'View details',
onClick: () => console.log('clicked'),
},
],
});
// Programmatically dismiss:
flag.close();
FlagOptions type:
{
id: string | number;
title?: string;
description?: string;
type?: 'info' | 'success' | 'warning' | 'error';
appearance?: 'info' | 'success' | 'warning' | 'error';
isAutoDismiss?: boolean;
actions?: Array<{ text: string; onClick: () => void }>;
}
fetch(url, options?)β
Standard browser fetch for calling external APIs. No special authentication β use public APIs or pass your own credentials.
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return JSON.stringify(data);
Code Patternsβ
Pattern: Paginated JQL search with all resultsβ
The default maxResults is 50. For large result sets, paginate with startAt:
const jql = 'project = "MY-PROJECT" AND status = "To Do"';
const maxResults = 100;
let startAt = 0;
let allIssues = [];
while (true) {
const response = await requestJira(
`/rest/api/3/search?jql=${encodeURIComponent(jql)}&maxResults=${maxResults}&startAt=${startAt}`,
{ headers: { 'Accept': 'application/json' } }
);
const data = await response.json();
allIssues = allIssues.concat(data.issues);
if (allIssues.length >= data.total) break;
startAt += maxResults;
}
return `Found ${allIssues.length} issues`;
Pattern: Bulk update with error loggingβ
let output = '';
for (const issueKey of issueKeys) {
const response = await requestJira(`/rest/api/3/issue/${issueKey}`, {
method: 'PUT',
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
body: JSON.stringify({ fields: { /* ... */ } }),
});
if (response.status === 204) {
output += `β ${issueKey} updated\n`;
} else {
const err = await response.json();
output += `β ${issueKey} failed: ${JSON.stringify(err.errorMessages)}\n`;
}
}
return output;
Pattern: Script output structureβ
return "some string"β shows a string in the result panelreturn JSON.stringify(obj)β shows formatted JSONconsole.log(...)β shows in the console log section- No return /
return undefinedβ result panel shows nothing
Complete Jira Examplesβ
Example 1: Call the Jira REST APIβ
'use strict';
const response = await requestJira('/rest/api/3/myself', {
headers: { 'Accept': 'application/json' },
});
const data = await response.json();
return JSON.stringify(data);
Example 2: Get a Jira issueβ
const issueIdOrKey = 'PROJ-1';
const response = await requestJira(`/rest/api/3/issue/${issueIdOrKey}`, {
headers: { 'Accept': 'application/json' },
});
const data = await response.json();
return JSON.stringify(data);
Example 3: Create a Jira issueβ
'use strict';
const payload = {
fields: {
summary: 'Sample issue created by Script Master',
issuetype: { id: '10002' },
project: { key: 'MC' },
description: {
type: 'doc',
version: 1,
content: [
{
type: 'paragraph',
content: [{ text: 'As a user, I want to...', type: 'text' }],
},
],
},
},
};
const response = await requestJira('/rest/api/3/issue', {
method: 'POST',
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
const data = await response.json();
return JSON.stringify(data);
Example 4: Update an issue (summary and labels)β
'use strict';
const issueKey = 'PROJ-42';
const response = await requestJira(`/rest/api/3/issue/${issueKey}`, {
method: 'PUT',
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
body: JSON.stringify({
update: {
labels: [{ add: 'triaged' }, { remove: 'blocker' }],
summary: [{ set: 'Updated summary text' }],
},
}),
});
return `Response: ${response.status} ${response.statusText}`;
Example 5: JQL searchβ
'use strict';
const jql = 'created > -7d';
const response = await requestJira(
`/rest/api/3/search?jql=${encodeURIComponent(jql)}`,
{ headers: { 'Accept': 'application/json' } }
);
const data = await response.json();
return data.issues.map(i => i.key).join(', ');
Example 6: Bulk change filter ownership (use case)β
'use strict';
// Configuration
const filterIds = [10001, 10002, 10008];
const newOwnerAccountId = 'ACCOUNT_ID_HERE';
let output = '';
for (const filterId of filterIds) {
const response = await requestJira(`/rest/api/3/filter/${filterId}/owner`, {
method: 'PUT',
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
body: JSON.stringify({ accountId: newOwnerAccountId }),
});
if (response.status === 204) {
output += `β Filter ${filterId}: ownership changed\n`;
} else {
const err = await response.json();
output += `β Filter ${filterId}: ${err.errorMessages}\n`;
}
}
return output;
Complete Confluence Examplesβ
Example 1: Call the Confluence REST APIβ
const response = await requestConfluence('/wiki/rest/api/user/current', {
headers: { 'Accept': 'application/json' },
});
const data = await response.json();
return JSON.stringify(data);
Example 2: Create a Confluence pageβ
const response = await requestConfluence('/wiki/api/v2/pages', {
method: 'POST',
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
body: JSON.stringify({
spaceId: 'SPACE_ID',
title: 'My New Page',
parentId: 'PARENT_PAGE_ID',
status: 'current',
body: {
representation: 'storage',
value: '<p>Hello, Confluence!</p>',
},
}),
});
console.log(`Response: ${response.status} ${response.statusText}`);
return JSON.stringify(await response.json());
Example 3: Permanently purge trashed pages from spaces (use case)β
// Configuration
const spaceKeys = ['HR', 'ITDOC'];
const spacesResponse = await requestConfluence(
`/wiki/api/v2/spaces?keys=${spaceKeys.join(',')}`,
{ headers: { 'Accept': 'application/json' } }
);
const spacesData = await spacesResponse.json();
if (!spacesData.results?.length) return 'Spaces not found';
let output = '';
for (const space of spacesData.results) {
const pagesResponse = await requestConfluence(
`/wiki/api/v2/pages?space-id=${space.id}&status=trashed&limit=250`,
{ headers: { 'Accept': 'application/json' } }
);
const pagesData = await pagesResponse.json();
for (const page of pagesData.results) {
const del = await requestConfluence(`/wiki/api/v2/pages/${page.id}?purge=true`, {
method: 'DELETE',
});
if (del.status === 204) {
output += `β Purged '${page.title}' from '${space.name}'\n`;
} else {
const err = await del.json();
output += `β Could not purge '${page.title}': ${JSON.stringify(err)}\n`;
}
}
}
return output || 'No trashed pages found';
Complete Bitbucket Exampleβ
Example 1: List repositories in the workspaceβ
const ctx = await view.getContext();
const response = await requestBitbucket(`/2.0/repositories/${ctx.workspaceId}`);
const data = await response.json();
return JSON.stringify(data);
Writing Good Scripts β Rulesβ
- Always use
returnto produce visible output in the result panel. Withoutreturn, the script runs silently. - Handle errors β check
response.statusbefore calling.json(). A non-2xx response may return HTML, not JSON. - Paginate β Jira's
/searchand Confluence's list endpoints cap at 50β250 results by default. Loop withstartAt/cursor for complete datasets. - Use
encodeURIComponentfor JQL and other query parameters that may contain spaces or special characters. - Structure output β build a
let output = ''string during loops;return outputat the end. - Comment configuration variables β put user-configurable values (IDs, keys, JQL strings) at the top with a
// Configurationcomment so users can easily adapt the script. - Avoid unnecessary
view.getContext()calls β use the pre-injectedcontextglobal instead (already fetched). - Rate limits β avoid firing hundreds of API calls in tight loops; consider
await-ing each call sequentially for safety.
Useful REST API Linksβ
Jira Cloud REST API v3β
- Search issues (JQL):
GET /rest/api/3/search?jql=...β docs - Get issue:
GET /rest/api/3/issue/{issueIdOrKey}β docs - Create issue:
POST /rest/api/3/issueβ docs - Update issue:
PUT /rest/api/3/issue/{issueIdOrKey}β docs - Get current user:
GET /rest/api/3/myselfβ docs - Get projects:
GET /rest/api/3/project/searchβ docs - Get filters:
GET /rest/api/3/filter/searchβ docs - Update filter owner:
PUT /rest/api/3/filter/{id}/ownerβ docs
Confluence REST API v2β
- Get current user:
GET /wiki/rest/api/user/current - Get spaces:
GET /wiki/api/v2/spaces - Get pages:
GET /wiki/api/v2/pages - Create page:
POST /wiki/api/v2/pagesβ docs - Update page:
PUT /wiki/api/v2/pages/{id} - Delete/purge page:
DELETE /wiki/api/v2/pages/{id}?purge=true
Bitbucket REST APIβ
- List repositories:
GET /2.0/repositories/{workspace}β docs