Skip to main content

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 await is supported β€” use it freely.
  • Use return to 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​

GlobalTypeDescription
requestJira(path, options?) => Promise<Response>Make authenticated calls to the Jira REST API
viewForge view objectAccess context and UI lifecycle
showFlag(options) => FlagShow a notification flag in the Jira UI
contextFullContext objectPre-fetched app context (user, cloud, extension info)
fetchWeb fetchCall any external HTTP endpoint
consoleStandard consoleconsole.log(), console.error(), etc.

Confluence​

GlobalTypeDescription
requestConfluence(path, options?) => Promise<Response>Make authenticated calls to the Confluence REST API
viewForge view objectAccess context and UI lifecycle
showFlag(options) => FlagShow a notification flag in the Confluence UI
contextFullContext objectPre-fetched app context
fetchWeb fetchCall any external HTTP endpoint
consoleStandard consoleconsole.log(), console.error(), etc.

Bitbucket​

GlobalTypeDescription
requestBitbucket(path, options?) => Promise<Response>Make authenticated calls to the Bitbucket REST API
viewForge view objectAccess context and UI lifecycle
showFlag(options) => FlagShow a notification flag in the Bitbucket UI
contextFullContext objectPre-fetched app context
fetchWeb fetchCall any external HTTP endpoint
consoleStandard consoleconsole.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 β€” standard fetch RequestInit options (method, headers, body), minus signal
  • Returns β€” a standard Response object
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 β€” standard fetch options
  • Returns β€” a standard Response object
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 Response object
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 context global is a pre-fetched snapshot of view.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 panel
  • return JSON.stringify(obj) β€” shows formatted JSON
  • console.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}`;
'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​

  1. Always use return to produce visible output in the result panel. Without return, the script runs silently.
  2. Handle errors β€” check response.status before calling .json(). A non-2xx response may return HTML, not JSON.
  3. Paginate β€” Jira's /search and Confluence's list endpoints cap at 50–250 results by default. Loop with startAt/cursor for complete datasets.
  4. Use encodeURIComponent for JQL and other query parameters that may contain spaces or special characters.
  5. Structure output β€” build a let output = '' string during loops; return output at the end.
  6. Comment configuration variables β€” put user-configurable values (IDs, keys, JQL strings) at the top with a // Configuration comment so users can easily adapt the script.
  7. Avoid unnecessary view.getContext() calls β€” use the pre-injected context global instead (already fetched).
  8. Rate limits β€” avoid firing hundreds of API calls in tight loops; consider await-ing each call sequentially for safety.

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