REST Endpoints
REST Endpoints let you create custom HTTP endpoints that execute ScriptForge scripts. External systems can call these endpoints to trigger actions in Jira, fetch data, or integrate with webhooks from third-party services.
How It Works
ScriptForge uses Forge Web Triggers to expose HTTP endpoints. When a request hits the endpoint URL, your script executes with full HAPI access and returns a response.
Creating a REST Endpoint
- Navigate to Apps → ScriptForge → REST Endpoints
- Click Create Endpoint
- Configure:
- Name — descriptive identifier
- Script — the handler logic
- Save — you'll receive a unique URL for the endpoint
Request and Response
Your script receives the incoming request and must return a response:
// Access the request
const method = context.request.method; // GET, POST, PUT, DELETE
const body = context.request.body; // Parsed JSON body
const queryParams = context.request.queryString; // URL parameters
// Return a response
return {
statusCode: 200,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ success: true, message: 'Done' })
};
Real-World Examples
Webhook Receiver — Create Issue from Alert
Receive alerts from a monitoring system and create Jira issues:
const alert = JSON.parse(context.request.body);
const issue = await WorkItems.create('OPS', 'Incident')
.setSummary(`[Alert] ${alert.title}`)
.setDescription(`Severity: ${alert.severity}\nSource: ${alert.source}\n\n${alert.message}`)
.setPriority(alert.severity === 'critical' ? 'Critical' : 'High')
.execute();
return {
statusCode: 201,
body: JSON.stringify({ created: issue.key })
};
Data Endpoint — Return Issue Statistics
Expose project statistics for an external dashboard:
const projectKey = context.request.queryString.project;
if (!projectKey) {
return { statusCode: 400, body: JSON.stringify({ error: 'project parameter required' }) };
}
const openBugs = await WorkItems.count(`project = "${projectKey}" AND type = Bug AND status != Done`);
const totalOpen = await WorkItems.count(`project = "${projectKey}" AND status != Done`);
return {
statusCode: 200,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
project: projectKey,
openBugs: openBugs,
totalOpen: totalOpen
})
};
Action Endpoint — Bulk Transition Issues
Receive a list of issue keys and transition them all:
const { issueKeys, transition } = JSON.parse(context.request.body);
if (!issueKeys || !transition) {
return { statusCode: 400, body: JSON.stringify({ error: 'issueKeys and transition required' }) };
}
const results = [];
for (const key of issueKeys) {
try {
const issue = await WorkItems.getByKey(key);
await issue.transition(transition);
results.push({ key, status: 'transitioned' });
} catch (err) {
results.push({ key, status: 'failed', error: err.message });
}
}
return {
statusCode: 200,
body: JSON.stringify({ results })
};
Integration — Sync Status to External System
Called by a CI/CD pipeline to update issue status after deployment:
const { issueKey, buildStatus, buildUrl } = JSON.parse(context.request.body);
const issue = await WorkItems.getByKey(issueKey);
const props = await issue.getEntityProperties();
await props.setString('ci-build-status', buildStatus);
await props.setString('ci-build-url', buildUrl);
await issue.addComment(`Build ${buildStatus}: ${buildUrl}`);
return { statusCode: 200, body: JSON.stringify({ updated: issueKey }) };
Security Considerations
- Web Trigger URLs are unique and unguessable, but anyone with the URL can call it
- Validate incoming request data — never trust external input
- Check for required fields before processing
- Return appropriate HTTP status codes (400 for bad requests, 500 for errors)
- Consider rate limiting in your script if the endpoint could be called frequently
Limitations
- Endpoints are stateless — each request is independent
- Execution time is limited by the ScriptForge runtime budget (22 seconds)
- Large payloads may be truncated; keep request/response bodies reasonable