Integration Setup Guide
This integration enables tickets on SDP On-Premise to automatically create issues in Jira Cloud. When a technician clicks the button on the SDP ticket details page, the process begins, and a new issue is created in Jira.
The technician clicks the "Create JIRA Ticket" button on the SDP ticket page.
The SDP Page Script retrieves the ticket ID from the URL and calls the Callback Function with the POST request.
Deluge script retrieves ticket details (subject, description, item, date, etc.) from the SDP API.
The callback function sends a POST request to the Jira REST API with the collected data.
An issue is created in Jira. The technician is shown a success/failure message.
| Information | Explanation | Example |
|---|---|---|
| SDP Server URL (local) | SDP's internal network address | https://itsm.firma.local |
| SDP Technician URL | The URL that technicians log in with. | https://itsm.firma.com.tr |
| SDP Auth Token | Authentication for the SDP API | XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX |
| Jira Domain | Atlassian instance address | firma.atlassian.net |
| Jira Service Account Email | The account will be used for API operations. | sdp-service@firma.com |
| Jira API Token | Atlassian API access key | ATATT3xFfGF0... |
| Jira Project Key | Target Jira project code | PROJECT_KEY |
| Jira Issue Type ID | Type of issue to be created | 10XXX |
A firewall rule is required to access Jira Cloud from the SDP server. If this step is skipped, a connection to Jira cannot be established from the Deluge script.
| Source | Aim | Port | Protocol | Direction |
|---|---|---|---|---|
| SDP Server | *.atlassian.net | 443 | HTTPS/TCP | Outbound |
| SDP Server | JIRA_DOMAIN.atlassian.net | 443 | HTTPS/TCP | Outbound |
curl -v https:// JIRA_DOMAIN .atlassian.net| Conclusion | Meaning | Task to be done |
|---|---|---|
| ✅ HTML/JSON response | Connection successful. | Continue |
| ❌ ConnectTimeoutException | The firewall is blocking it. | Have IT create a firewall rule. |
| ⚠️ SSL error | Certificate issue | Check your SSL settings. |
Run the following test script under SDP Admin > Automation > Custom Functions:
testUrl = "https:// JIRA_DOMAIN .atlassian.net";
response = invokeurl
[
url: testUrl
type: GET
];
info response.toString();
return response.toString();
Go to https://id.atlassian.com/manage-profile/security/api-tokens .
Click the "Create API Token" button. Give the token a meaningful name (e.g., SDP Integration).
Copy the generated token. This token will not be shown again!
Jira REST API uses a combined Base64 encoding of email and API token for Basic Auth.
echo -n " email@firma.com : API_TOKEN " | base64
Go to https://www.base64encode.org . Enter email@firma.com :API_TOKEN and click the "Encode" button.
Basic :headers.put("Authorization", "Basic BASE64_STRING ");curl --request GET \
--url "https:// JIRA_DOMAIN .atlassian.net/rest/api/3/project/search" \
--user " email@firma.com : API_TOKEN " \
--header "Accept: application/json"
curl --request GET \
--url "https:// JIRA_DOMAIN .atlassian.net/rest/api/3/issuetype/project?projectId= PROJECT_ID " \
--user " email@firma.com : API_TOKEN " \
--header "Accept: application/json"
curl --request GET \
--url "https:// JIRA_DOMAIN .atlassian.net/rest/api/3/field" \
--user " email@firma.com : API_TOKEN " \
--header "Accept: application/json"
In Response, find the corresponding "id" values by searching for the domain names. Example:
| Domain Name | Field ID Format | Medicine |
|---|---|---|
| Ticket Number Field | customfield_XXXXX | Number |
| Transaction Code / Fiori / Report | customfield_XXXXX | Text |
| Demand Channel | customfield_XXXXX | Dropdown |
| Responsible Modules | customfield_XXXXX | Multiselect |
| Business Unit | customfield_XXXXX | Group picker |
| Error Detection Date | customfield_XXXXX | Date (yyyy-MM-dd) |
Method: POST | URL: https://JIRA_DOMAIN.atlassian.net/rest/api/3/issue
Authorization: Basic Auth | Username: email | Password: api_token
{
"fields": {
"project": { "key": " PROJE_KEY " },
"issuetype": { "id": " ISSUE_TYPE_ID " },
"summary": "Test Ticket",
"description": {
"type": "doc", "version": 1,
"content": [{
"type": "paragraph",
"content": [{ "type": "text", "text": "Test description" }]
}]
},
"customfield_ XXXXX ": "value"
}
}{"id":"XXXXX","key":"PROJE-XXX","self":"..."} .The Callback Function is the structure that contains the Deluge script to send a POST request to the Jira API. PageScript triggers this function by calling it via the URL.
Admin > General Settings > Automation > Callback Functions > New
| Area | Value to be entered | Explanation |
|---|---|---|
| Function Name | Create Jira Issue | Name to be given to the function |
| Return Type | Map | Select Map from the dropdown menu. |
| API Name | create_jira_issue | Only letters, numbers, and underlines. |
| Publish | ✅ Marked | The checkbox must be checked! |
| Parameters - Name | request_id | Parameter name |
| Parameters - Type | string | Parameter type |
// ============================================
// SDP -> Jira Cloud Integration
// Callback Custom Function
// ============================================
// 1. Retrieve ticket information from the SDP API
sdpUrl = "https:// SDP_LOKAL_URL /api/v3/requests/" + request_id;
sdpHeaders = {
"authtoken": " SDP_AUTH_TOKEN ",
"PORTALID": "1"
};
sdpResponse = invokeurl
[
url: sdpUrl
type: GET
headers: sdpHeaders
];
requestObj = sdpResponse.get("request");
// 2. Item - Module Mapping
// Update according to customer environment.
modulMap = Map();
modulMap.put(" SDP_ITEM_NAME_1 ", " JIRA_MODULE_VALUE_1 ");
modulMap.put(" SDP_ITEM_NAME_2 ", " JIRA_MODULE_VALUE_2 ");
// Add other items here...
sdpItem = requestObj.get("item").get("name");
sdpModul = moduleMap.get(sdpItem);
if(sdpModul == null || sdpModul == "")
{
sdpModul = " DEFAULT_MODUL ";
}
// 3. Obtain SDP areas
sdpSubject = requestObj.get("subject");
// Clean the description from the HTML.
sdpDescriptionRaw = requestObj.get("description");
sdpDescription = sdpDescriptionRaw
.replaceAll("<[^>]*>", "")
.replaceAll(" ", " ")
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">");
sdpTicketID = requestObj.get("id");
// Convert historical data to Jira format (yyyy-MM-dd)
sdpDetectDateRaw = requestObj.get("created_time").get("display_value");
sdpDetectDate = sdpDetectDateRaw
.toDate("MMM dd, yyyy hh:mm a")
.toString("yyyy-MM-dd");
// 4. Send a POST request to the Jira API
jiraUrl = "https:// JIRA_DOMAIN .atlassian.net/rest/api/3/issue";
headers = Map();
headers.put("Authorization", "Basic BASE64_STRING ");
headers.put("Content-Type", "application/json");
body = "{\"fields\":{" +
"\"project\":{\"key\":\" PROJE_KEY \"}," +
"\"issuetype\":{\"id\":\" ISSUE_TYPE_ID \"}," +
"\"summary\":\"" + sdpSubject + "\"," +
"\"description\":{\"type\":\"doc\",\"version\":1," +
"\"content\":[{\"type\":\"paragraph\"," +
"\"content\":[{\"type\":\"text\"," +
"\"text\":\"" + sdpDescription + "\"}]}]}," +
"\" customfield_TICKET_NO_ID \":" + sdpTicketID + "," +
"\" customfield_ISLEM_KODU_ID \":\"-\"," +
"\" customfield_MODUL_ID \":[{\"value\":\"" + sdpModul + "\"}]," +
"\" customfield_IS_UNIT_ID \":[{\"name\":\" IS_UNIT_VALUE \"}]," +
"\" customfield_DATE_ID \":\"" + sdpDetectDate + "\"" +
"}}";
response = invokeurl
[
url: jiraUrl
type: POST
parameters: body
headers: headers
content-type: "application/json"
];
// 5. Return the result
returnObj = Collection();
if(response.get("key") != null)
{
returnObj.insert("result":"success");
returnObj.insert("message":"Jira issue created: " + response.get("key"));
}
else
{
returnObj.insert("result":"failure");
returnObj.insert("message":"Error: " + response.toString());
}
return returnObj;
| Variable | Explanation | How to Find It |
|---|---|---|
SDP_LOKAL_URL | SDP's internal network address | SDP server configuration |
SDP_AUTH_TOKEN | SDP API authentication token | SDP Admin > API Token |
JIRA_DOMAIN | Jira subdomain | From Jira URL |
BASE64_STRING | email:token base64 equivalent | Section 3.2 |
PROJE_KEY | Jira project code | Jira project settings |
ISSUE_TYPE_ID | Issue type numerical ID | Jira API /issuetype endpoint |
customfield_TICKET_NO_ID | Ticket number field ID | Jira API /field endpoint |
customfield_MODUL_ID | The ID of the responsible module area. | Jira API /field endpoint |
customfield_IS_BIRIMI_ID | Business unit field ID | Jira API /field endpoint |
customfield_TARIH_ID | Date field ID | Jira API /field endpoint |
IS_BIRIMI_DEGERI | The band name in Jira | Jira group settings |
VARSAYILAN_MODUL | To be used if mapping fails. | Determined according to the customer. |
PageScript adds a "Create JIRA Ticket" button to the SDP ticket details page. When the technician clicks the button, the Callback Function is triggered.
Admin > General Settings > Page Scripts > New
| Area | Value |
|---|---|
| Rule Name | Create Jira Button |
| Apply for | Technicians |
| Page | Request Details Page |
| Condition | It can be left blank if not needed. |
// ============================================
// SDP -> Jira Cloud | Page Script
// Request Details Page - Create Jira Button
// ============================================
$CS.addButton("edit", "Create JIRA Ticket", function(){
// Get Ticket ID from URL
var woID = window.location.href.match(/woID=(\d+)/);
var requestId = woID ? woID[1] : null;
if(!requestId){
alert("Request ID could not be received!");
return;
}
// Callback Function URL
// NOTE: The technician's access URL must be in the same domain as the CORS (Coordinated Domain)
var callbackUrl = "https:// SDP_TEKNISYEN_URL /AppIntegrations" +
"?serviceName=callbackFunctions" +
"&api_name=create_jira_issue" +
"&auth_token= CALLBACK_AUTH_TOKEN " +
"&PORTALID=1";
// Encode arguments and send via POST
var bodyData = "arguments=" +
encodeURIComponent('{"request_id":"' + requestId + '"}');
var promise = fetch(callbackUrl, {
method: "POST",
headers: {"Content-Type": "application/x-www-form-urlencoded"},
body: bodyData
});
promise.then(function(response){
return response.text();
}).then(function(text){
try {
var result = JSON.parse(text);
var output = result.output;
if(output && output.result === "success"){
alert("Jira ticket successfully created!\n" + output.message);
} else {
alert("Could not create Jira ticket!\n" +
(output ? output.message : text));
}
} catch(e){
alert("Server response: " + text);
}
}).catch(function(err){
alert("Connection error: " + err);
});
}, {
"class": "btn btn-default btn-xs ml10",
"style": "background-color: #e57373; color: white; border-color: #e57373;"
});
Go to Admin > General Settings > Automation > Callback Functions.
Turn on the "create_jira_issue" function.
Copy the URL from the "URL to execute this Custom Function" field.
Copy auth_token=... parameter from the URL and paste it into PageScript.
https://itsm.firma.com.tr , the same domain should be used in the callback URL.| Error Message | From where | Solution |
|---|---|---|
ConnectTimeoutException | The firewall is blocking it. | Apply the firewall rule from Section 2. |
401 Unauthorized | API token is faulty. | Renew the token, rebuild Base64. |
400 Bad Request | JSON parsing error / special character | Check replaceAll lines. |
404 Not Found | Callback not published. | Check the Publish checkbox. |
Failed to fetch | CORS error - different domain | Make the PageScript URL the same as the technician URL. |
415 Unsupported Media Type | Content-Type is incorrect. | add content-type: "application/json" |
undefined message | response.output path error | Use result.output.message |
| The module is coming empty. | Item mapping is missing. | Add a new item-module pair to modulMap |
| Date formatting error | History cannot be parsed. | Update toDate format string to match the format received from SDP. |
testUrl = "https:// JIRA_DOMAIN .atlassian.net/rest/api/3/myself";
headers = Map();
headers.put("Authorization", "Basic BASE64_STRING ");
response = invokeurl
[
url: testUrl
type: GET
headers: headers
];
info response.toString();
return response.toString();
accountId and emailAddress .Complete the following steps in order for each new customer installation.