This guide contains different examples of how to use the Jira REST API, including how to query issues, create an issue, edit an issue, and others.
The reference documentation for the Jira Data Center REST API is here: Jira Data Center REST API. If you've never used the Jira REST APIs before, we recommend that you also read the overview About the Jira REST APIs.
The examples on this page use curl. If an input file is required, it is denoted by the
--data @filename
syntax and the file data is shown separately.
Note that the createmeta
resource has been reported to cause issues especially on larger instances. These issues have involved the size of the response or Jira running out of memory.
That is why we decided to remove this endpoint in Jira 9.0. If you run Jira 8.4 or later, disable the endpoint and replace it with the other calls we've created to remedy the issue. For Jira versions earlier than 8.4, you do not need to disable the endpoint but we strongly recommend that you upgrade to a newer Jira version. Read more ...
Creating an issue using the Jira REST API is as simple as making a POST with a JSON document. To create an issue,
you will need to know certain key metadata, like the ID of the project that the issue will be created in, or the
ID of the issue type. You can request the create metadata for all issue types across all projects by using
the createmeta
resource.
For example:
1 2http://localhost:8080/rest/api/2/issue/createmeta
If you only want a subset of this information, specify the desired projects and issue types as query parameters. For example, this request will return the create metadata for the Bug issue type in the Jira project:
1 2http://localhost:8080/rest/api/2/issue/createmeta?projectKeys=JRA&issuetypeNames=Bug&expand=projects.issuetypes.fields
For more detailed examples of requesting metadata, see the examples in the sections later.
Creating an issue using the Jira REST API is as simple as making a POST with a JSON document. To create an issue, you will need to know certain key metadata, like the ID of the project that the issue will be created in, the ID of the issue type, and which fields to fill. First, you need to decide which project to use. You can get a list of all the projects from the following endpoint:
1 2http://localhost:8080/rest/api/2/project
After finding the project you want, you will need its ID or key. You will use this information to retrieve the issue types in this project:
1 2http://localhost:8080/rest/api/2/issue/createmeta/{projectIdOrKey}/issuetypes
Once you find the appropriate issue type to use, you need to get the fields under this issue type. This endpoint will list the usable fields under the issue type.
1 2http://localhost:8080/rest/api/2/issue/createmeta/{projectIdOrKey}/issuetypes/{issueTypeId}
For more detailed examples of requesting metadata, see the examples in the sections later.
This is a basic example of how to create an issue using the Jira REST API.
1 2curl \ -D- \ -u charlie:charlie \ -X POST \ --data {see below} \ -H "Content-Type: application/json" \ http://localhost:8080/rest/api/2/issue/
1 2{ "fields": { "project": { "key": "TEST" }, "summary": "REST ye merry gentlemen.", "description": "Creating of an issue using project keys and issue type names using the REST API", "issuetype": { "name": "Bug" } } }
1 2{ "id":"39000", "key":"TEST-101", "self":"http://localhost:8080/rest/api/2/issue/39000" }
This example uses the project ID and issue type ID rather than the key and name respectively. This is useful if you only have the IDs. For example, your integration or script may have previously requested and saved only the IDs of the project and issue type.
1 2curl \ -D- \ -u charlie:charlie \ -X POST \ --data {see below} \ -H "Content-Type: application/json" \ http://localhost:8080/rest/api/2/issue/
1 2{ "fields": { "project": { "id": "10110" }, "summary": "No REST for the Wicked.", "description": "Creating of an issue using IDs for projects and issue types using the REST API", "issuetype": { "id": "1" } } }
The response provides the issue ID, key, and the URL to the issue. You can use this to GET additional data, PUT updates, and so on via the REST API.
1 2{ "id":"39001", "key":"TEST-102", "self":"http://localhost:8080/rest/api/2/issue/39001" }
A sub-task is essentially a special type of issue, so the sub-task creation request and response are very similar to issue creation. Creating a sub-task has two important differences:
issueType
field must correspond to a sub-task issue type
(you can use /issue/createmeta
to discover sub-task issue types).parent
field in the issue create request containing the ID or key
of the parent issue.issueType
field must correspond to a sub-task issue type
(you can use /issue/createmeta/{projectIdOrKey}/issuetypes
to discover sub-task issue types).parent
field in the issue create request containing the ID or key
of the parent issue.1 2curl \ -D- \ -u charlie:charlie \ -X POST \ --data {see below} \ -H "Content-Type: application/json" \ http://localhost:8080/rest/api/2/issue/
1 2{ "fields": { "project": { "key": "TEST" }, "parent": { "key": "TEST-101" }, "summary": "Sub-task of TEST-101", "description": "Don't forget to do this too.", "issuetype": { "id": "5" } } }
The response provides the sub-task ID, key, and the URL to the issue (which can then be used to GET additional data, PUT updates, and so on) via the REST API.
1 2{ "id":"39002", "key":"TEST-103", "self":"http://localhost:8080/rest/api/2/issue/39002" }
In the Jira REST API, custom fields are uniquely identified by the field ID, as the display names are not unique within a Jira instance. For example, you could have two fields named "Escalation date", one with an ID of "12221" and one with an ID of "12222".
A custom field is actually referenced by customfield\_
+ the field ID, rather than just the field ID.
For example, the "Story points" custom field with ID = "10000" is referenced as customfield\_10000
for REST calls.
You can get this reference identifier by requesting the create metadata for the issue type.
The example below uses a custom free text field named "Explanation" that has an ID of 11050. Note that we
reference the field by customfield\_11050
and that the name of the field "Explanation" is not used anywhere.
1 2curl \ -D- \ -u charlie:charlie \ -X POST \ --data {see below} \ -H "Content-Type: application/json" \ http://localhost:8080/rest/api/2/issue/
1 2{ "fields": { "project": { "key": "TEST" }, "summary": "Always do right. This will gratify some people and astonish the REST.", "description": "Creating an issue while setting custom field values", "issuetype": { "name": "Bug" }, "customfield_11050" : "Value that we're putting into a Free Text Field." } }
Again, the issue created is returned in the response.
1 2{ "id":"39002", "key":"TEST-103", "self":"http://localhost:8080/rest/api/2/issue/TEST-103" }
The examples below show how to set the values for different types of custom fields in the input data.
For Jira versions earlier than 8.4 you should retrieve custom field ID from the createmeta
endpoint.
For Jira versions 8.4 and later you should retrieve custom field ID from the /issue/createmeta/{projectIdOrKey}/issuetypes/{issueTypeId}
endpoint.
1 2"customfield_10001": {"value": "green", "child": {"value":"blue"} }
The value associated with "name" ("green" in this example) is the parent option selected, then "blue" is the child option).
1 2"customfield_10002": "2011-10-03"
The format is: YYYY-MM-DD
1 2"customfield_10003": "2011-10-19T10:29:29.908+1100"
This format is ISO 8601: YYYY-MM-DDThh:mm:ss.sTZD
1 2"customfield_10004": "Free text goes here. Type away!"
1 2"customfield_10005": { "name": "jira-developers" }
Like users, groups are specified by name or ID.
1 2"customfield_10007": [{ "name": "admins" }, { "name": "jira-developers" }, { "name": "jira-users" }]
Like users, groups are specified by name or ID.
1 2"customfield_10008": [ {"value": "red" }, {"value": "blue" }, {"value": "green" }]
1 2"customfield_10009": [ {"name": "charlie" }, {"name": "bjones" }, {"name": "tdurden" }]
Array of users.
1 2"customfield_10010": 42.07
Just a number (not a number in a string).
1 2"customfield_10011": { "key": "JRADEV" }
You can also specify the project by project ID.
1 2{ "id":"10000" }
1 2"customfield_10012": { "value": "red" }
You can also specify the selection by ID.
1 2"customfield_10013": { "value": "red" }
You can also specify the selection by ID.
1 2"customfield_10014": { "name": "5.0" }
You can also specify the version by ID.
1 2"customfield_10015": "Is anything better than text?"
1 2"customfield_10016": "http://www.atlassian.com"
1 2"customfield_10017": { "name":"brollins" }
1 2"customfield_10018": [{ "name": "1.0" }, { "name": "1.1.1" }, { "name": "2.0" }]
You can also specify a version by ID.
If you want to set the time tracking fields in a Jira issue when creating the issue, the create data should include a section like the following:
1 2"timetracking": { "originalEstimate": "1d 2h", "remainingEstimate": "3h 25m" }
Time tracking must be enabled to set these fields. In addition, if you use the Jira "Legacy" time tracking mode
(set by a Jira Administrator), then only the remaining estimate can be set, so the originalestimate
field
should not be included in the REST request.
The same as the other examples, the create is a POST:
1 2curl \ -D- \ -u charlie:charlie \ -X POST \ --data {see below} \ -H "Content-Type: application/json" \ http://localhost:8080/rest/api/2/issue/
Again, this data is if Legacy mode for time tracking is off.
1 2{ "fields": { "project": { "key": "TEST" }, "summary": "Who seeks a faultless friend RESTs friendless.", "description": "Creating an issue and setting time tracking fields", "issuetype": { "name": "Bug" }, "timetracking": { "originalEstimate": "1d 2h", "remainingEstimate": "3h 25m" } } }
1 2{ "id":"39003", "key":"TEST-104", "self":"http://localhost:8080/rest/api/2/issue/TEST-104" }
The examples in this section show you how to edit an existing issue using the Jira REST API. There are two types of examples in this section:
To edit an issue, you need to know certain key metadata, like the editable fields and the operations that they support.
You can request this data for an issue by using the editmeta
resource. For example:
1 2http://localhost:8080/rest/api/2/issue/JRA-13/editmeta
Note that the editmeta
resource does not work with PUT operations. You should only use it to get data.
This example assigns an issue to a user with the username "charlie".
1 2curl \ -D- \ -u charlie:charlie \ -X PUT \ --data {see below} \ -H "Content-Type: application/json" \ http://localhost:8080/rest/api/2/issue/QA-31
1 2{ "fields": { "assignee":{"name":"charlie"} } }
Status code of "204 No Content".
This example updates the summary, description, and two custom fields.
1 2curl \ -D- \ -u charlie:charlie \ -X PUT \ --data {see below} \ -H "Content-Type: application/json" \ http://localhost:8080/rest/api/2/issue/QA-31
1 2{ "fields" : { "summary": "Summary", "description": "Description", "customfield_10200" : "Test 1", "customfield_10201" : "Value 1" } }
Status code of "204 No Content".
1 2curl \ -D- \ -u charlie:charlie \ -X PUT \ --data {see below} \ -H "Content-Type: application/json" \ http://localhost:8080/rest/api/2/issue/QA-31
example input data
1 2{ "update" : { "components" : [{"add" : {"name" : "Engine"}}] } }
Status code of "204 No Content".
1 2curl \ -D- \ -u charlie:charlie \ -X PUT \ --data {see below} \ -H "Content-Type: application/json" \ http://localhost:8080/rest/api/2/issue/QA-31
This is an example input data:
1 2{ "update" : { "components" : [{"set" : [{"name" : "Engine"}, {"name" : "Trans/A"}]}] } }
Status code of "204 No Content".
1 2curl \ -D- \ -u charlie:charlie \ -X PUT \ --data {see below} \ -H "Content-Type: application/json" \ http://localhost:8080/rest/api/2/issue/QA-31
This is an example input data:
1 2{ "update" : { "components" : [{"remove" : {"name" : "Trans/A"}}, {"add" : {"name" : "Trans/M"}}] } }
Note: The "Engine" component (if it exists) remains unaffected by this update.
Status code of "204 No Content".
1 2curl \ -D- \ -u charlie:charlie \ -X PUT \ --data {see below} \ -H "Content-Type: application/json" \ http://localhost:8080/rest/api/2/issue/QA-31
This is an example input data:
1 2{ "update" : { "components" : [{"remove" : {"name" : "Trans/A"}}, {"add" : {"name" : "Trans/M"}}], "assignee" : [{"set" : {"name" : "harry"}}], "summary" : [{"set" : "Big block Chevy"}] } }
Status code of "204 No Content".
The examples in this section show you how to add a comment to an existing issue using the Jira REST API. There are two types of examples in this section:
comment
resource. This resource simply adds a comment and nothing else. It is
also possible to add a comment as a side-effect of another operation like "edit issue" or "transition issue".
This resource is particularly useful if the logged in user does not have "edit" permission for the issue, but does
have the "add comment" permission. Examples:
* Adding a comment.
* Adding a comment and setting the security level in the same request.1 2* Adding a comment using the edit issue method.
1 2* Adding a comment and updating the issue description using the edit issue method.
This example request adds a comment to an existing issue.
1 2curl \ -D- \ -u fred:fred \ -X POST \ --data {see below} \ -H "Content-Type: application/json" \ http://localhost:8081/rest/api/2/issue/QA-31/comment
This is an example input data:
1 2{ "body": "This is a comment regarding the quality of the response." }
You should just receive a response with a status of "201" with the full JSON representation of the added comment.
This example request adds a comment and sets the security level to an existing issue.
1 2curl \ -D- \ -u fred:fred \ -X POST \ --data {see below} \ -H "Content-Type: application/json" \ http://localhost:8081/rest/api/2/issue/QA-31/comment
1 2{ "body": "This is a comment that only administrators can see.", "visibility": { "type": "role", "value": "Administrators" } }
This example request adds a comment to an existing issue via the edit issue method. Note that only one comment at a time can be added when updating an issue via this resource.
1 2curl \ -D- \ -u fred:fred \ -X PUT \ --data {see below} \ -H "Content-Type: application/json" \ http://localhost:8081/rest/api/2/issue/QA-31
1 2{ "update": { "comment": [ { "add": { "body": "It is time to finish this task" } } ] } }
This example request updates the description of an existing issue and adds a comment explaining why via the edit issue method.
1 2curl \ -D- \ -u fred:fred \ -X PUT \ --data {see below} \ -H "Content-Type: application/json" \ http://localhost:8081/rest/api/2/issue/QA-31
1 2{ "update": { "description": [ { "set": "JIRA should also come with a free pony" } ], "comment": [ { "add": { "body": "This request was originally written in French, which most of our developers can't read" } } ] } }
The examples in this section show you how to search for issues using JQL via the Jira REST API.
Examples in this section:
This example request searches for issues assigned to a user with the username "charlie".
A single URL parameter (jql
) that contains the JQL query is provided in the request.
1 2curl \ -D- \ -u charlie:charlie \ -X GET \ -H "Content-Type: application/json" \ http://localhost:8080/rest/api/2/search?jql=assignee=charlie
1 2{ "expand": "schema,names", "startAt": 0, "maxResults": 50, "total": 6, "issues": [ { "expand": "html", "id": "10230", "self": "http://localhost:8080/rest/api/2/issue/BULK-62", "key": "BULK-62", "fields": { "summary": "testing", "timetracking": null, "issuetype": { "self": "http://localhost:8080/rest/api/2/issuetype/5", "id": "5", "description": "The sub-task of the issue", "iconUrl": "http://localhost:8080/images/icons/issue_subtask.gif", "name": "Sub-task", "subtask": true }, . . . }, "customfield_10071": null }, "transitions": "http://localhost:8080/rest/api/2/issue/BULK-62/transitions", }, { "expand": "html", "id": "10004", "self": "http://localhost:8080/rest/api/2/issue/BULK-47", "key": "BULK-47", "fields": { "summary": "Cheese v1 2.0 issue", "timetracking": null, "issuetype": { "self": "http://localhost:8080/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:8080/images/icons/task.gif", "name": "Task", "subtask": false }, . . . "transitions": "http://localhost:8080/rest/api/2/issue/BULK-47/transitions", } ] }
This example request searches for issues assigned to a user with the username "charlie" and restricts the number of results to a specified number of issues.
Two additional URL parameters are provided in the request: startAt
and maxResults.
These parameters specify
the starting issue returned in the JQL results and the number of issues from that starting issue respectively.
1 2curl \ -D- \ -u charlie:charlie \ -X GET \ -H "Content-Type: application/json" \ http://localhost:8080/rest/api/2/search?jql=assignee=charlie&startAt=2&maxResults=2
1 2{ "expand": "schema,names", "startAt": 2, "maxResults": 2, "total": 6, "issues": [ { "expand": "html", "id": "10123", "self": "http://localhost:8080/rest/api/2/issue/BULK-38", "key": "BULK-38", "fields": { "summary": "aaaaa", "timetracking": null, "issuetype": { "self": "http://localhost:8080/rest/api/2/issuetype/5", "id": "5", "description": "The sub-task of the issue", "iconUrl": "http://localhost:8080/images/icons/issue_subtask.gif", "name": "Sub-task", "subtask": true }, . . . }, "transitions": "http://localhost:8080/rest/api/2/issue/BULK-38/transitions", }, { "expand": "html", "id": "10108", "self": "http://localhost:8080/rest/api/2/issue/BULK-32", "key": "BULK-32", "fields": { "summary": "subtasks are important, too", "timetracking": null, "issuetype": { "self": "http://localhost:8080/rest/api/2/issuetype/5", "id": "5", "description": "The sub-task of the issue", "iconUrl": "http://localhost:8080/images/icons/issue_subtask.gif", "name": "Sub-task", "subtask": true }, . . . }, "transitions": "http://localhost:8080/rest/api/2/issue/BULK-32/transitions", } ] }
This example request searches for issues assigned to a user with the username "charlie" and orders the returned
issues by due date. The ordering is specified by using an order by
clause in the JQL query itself
(not via a URL parameter in your REST API call).
1 2curl \ -D- \ -u charlie:charlie \ -X GET \ -H "Content-Type: application/json" \ http://localhost:8080/rest/api/2/search?jql=assignee=charlie+order+by+duedate
1 2{ "expand": "schema,names", "startAt": 0, "maxResults": 50, "total": 6, "issues": [ { "expand": "html", "id": "10123", "self": "http://localhost:8080/rest/api/2/issue/BULK-38", "key": "BULK-38", "fields": { "summary": "aaaaa", "timetracking": null, "issuetype": { "self": "http://localhost:8080/rest/api/2/issuetype/5", "id": "5", "description": "The sub-task of the issue", "iconUrl": "http://localhost:8080/images/icons/issue_subtask.gif", "name": "Sub-task", "subtask": true }, . . . }, "transitions": "http://localhost:8080/rest/api/2/issue/BULK-38/transitions", }, { "expand": "html", "id": "10108", "self": "http://localhost:8080/rest/api/2/issue/BULK-32", "key": "BULK-32", "fields": { "summary": "subtasks are important, too", "timetracking": null, "issuetype": { "self": "http://localhost:8080/rest/api/2/issuetype/5", "id": "5", "description": "The sub-task of the issue", "iconUrl": "http://localhost:8080/images/icons/issue_subtask.gif", "name": "Sub-task", "subtask": true }, . . . }, "transitions": "http://localhost:8080/rest/api/2/issue/BULK-32/transitions", } ] }
This example request searches for issues assigned to a user with the username "charlie" and restricts the issue
fields returned to a specified set. The fields restriction is specified by supplying an additional URL parameter
fields
, which lists the Jira fields returned in the JQL results.
Each Jira field in the list should be comma-separated, for example, fields=id,key
.
Keep in mind that some extra data is always returned in the JSON response.
1 2curl \ -D- \ -u charlie:charlie \ -X GET \ -H "Content-Type: application/json" \ 'http://localhost:8080/rest/api/2/search?jql=project=QA+order+by+duedate&fields=id,key'
1 2{ "expand": "schema,names", "startAt": 0, "maxResults": 50, "total": 18, "issues": [ { "expand": "html", "id": "10050", "self": "http://localhost:8080/rest/api/2/issue/QA-19", "key": "QA-19", "transitions": "http://localhost:8080/rest/api/2/issue/QA-19/transitions" }, { "expand": "html", "id": "10051", "self": "http://localhost:8080/rest/api/2/issue/QA-20", "key": "QA-20", "transitions": "http://localhost:8080/rest/api/2/issue/QA-20/transitions" }, . . . { "expand": "html", "id": "10053", "self": "http://localhost:8080/rest/api/2/issue/QA-22", "key": "QA-22", "transitions": "http://localhost:8080/rest/api/2/issue/QA-22/transitions" }, { "expand": "html", "id": "10389", "self": "http://localhost:8080/rest/api/2/issue/QA-35", "key": "QA-35", "transitions": "http://localhost:8080/rest/api/2/issue/QA-35/transitions" } ] }
If your JQL query is too large to specify in a URL parameter, you can POST your JQL query (in JSON format) to
the Jira REST API search
resource instead.
Any additional URL parameters (apart from the url
parameter) described above must be included in your
JSON-formatted JQL query.
1 2curl \ -D- \ -u admin:admin \ -X POST \ -H "Content-Type: application/json" \ --data '{"jql":"project = QA","startAt":0,"maxResults":2,"fields":["id","key"]}' \ "http://localhost:8080/rest/api/2/search"
1 2{ "maxResults": 2, "startAt": 0, "total": 18, "expand": "schema,names", "issues": [ { "expand": "html", "id": "10393", "key": "QA-36", "self": "http://localhost:8080/rest/api/2/issue/QA-36", "transitions": "http://localhost:8080/rest/api/2/issue/QA-36/transitions" }, { "expand": "html", "id": "10389", "key": "QA-35", "self": "http://localhost:8080/rest/api/2/issue/QA-35", "transitions": "http://localhost:8080/rest/api/2/issue/QA-35/transitions" } ] }
The Jira REST API allows you to discover the fields and data available and required for creating issues.
For this we use the createmeta
resource.
Examples in this section:
To create an issue in Jira, you first need to specify a project and issue type. These together are referred to in Jira as an Issue context and are used to find the Jira schemes that control what fields are available for an issue, what the default values are, and what fields are mandatory.
Using the createmeta
resource you can discover the project and issue types.
1 2curl \ -D- \ -u fred:fred \ -X GET \ -H "Content-Type: application/json" \ http://localhost:8081/rest/api/2/issue/createmeta
The response consists of an array of projects and each project contains an array of issue types that apply to that project.
1 2{ "expand": "projects", "projects": [ { "self": "http://localhost:8081/rest/api/2/project/XSS", "id": "10020", "key": "XSS", "name": "<iframe src=\"http://www.google.com\"></iframe>", "avatarUrls": { "16x16": "http://localhost:8081/secure/projectavatar?size=small&pid=10020&avatarId=10011", "48x48": "http://localhost:8081/secure/projectavatar?pid=10020&avatarId=10011" }, "issuetypes": [ { "self": "http://localhost:8081/rest/api/2/issuetype/1", "id": 1, "name": "Bug", "iconUrl": "http://localhost:8081/images/icons/bug.gif" }, { "self": "http://localhost:8081/rest/api/2/issuetype/2", "id": 2, "name": "New Feature", "iconUrl": "http://localhost:8081/images/icons/newfeature.gif" }, . . . { "self": "http://localhost:8081/rest/api/2/issuetype/5", "id": 5, "name": "Sub-task", "iconUrl": "http://localhost:8081/images/icons/issue_subtask.gif" } ] }, { "self": "http://localhost:8081/rest/api/2/project/BULK", "id": "10000", "key": "BULK", "name": "Bulk Move 1", "avatarUrls": { "16x16": "http://localhost:8081/secure/projectavatar?size=small&pid=10000&avatarId=10020", "48x48": "http://localhost:8081/secure/projectavatar?pid=10000&avatarId=10020" }, "issuetypes": [ { "self": "http://localhost:8081/rest/api/2/issuetype/1", "id": 1, "name": "Bug", "iconUrl": "http://localhost:8081/images/icons/bug.gif" }, . . . { "self": "http://localhost:8081/rest/api/2/issuetype/5", "id": 5, "name": "Sub-task", "iconUrl": "http://localhost:8081/images/icons/issue_subtask.gif" } ] }, { "self": "http://localhost:8081/rest/api/2/project/BLUK", "id": "10001", "key": "BLUK", "name": "Bulk Move 2", "avatarUrls": { . . . . } ] }
If you know the projects or issue types you are interested in, you can restrict the list using the
projectKeys
, projectIds
, issuetypeNames
, and issuetypeIds
query parameters.
For example:
1 2curl \ -D- \ -u fred:fred \ -X GET \ -H "Content-Type: application/json" \ http://localhost:8081/rest/api/2/issue/createmeta?projectKeys=QA,XSS
When you have a project and issue type, you can retrieve the information for the issue fields by supplying
the expand
query parameter with the projects.issuetypes.fields
value.
1 2curl \ -D- \ -u fred:fred \ -X GET \ -H "Content-Type: application/json" \ http://localhost:8081/rest/api/2/issue/createmeta?projectKeys=QA&issuetypeNames=Bug&expand=projects.issuetypes.fields
The response consists of an array of projects and each project contains an array of issue types that apply to that project.
1 2{ "expand": "projects", "projects": [ { "expand": "issuetypes", "self": "http://localhost:8081/rest/api/2/project/QA", "id": "10010", "key": "QA", "name": "QA", "avatarUrls": { "16x16": "http://localhost:8081/secure/projectavatar?size=small&pid=10010&avatarId=10011", "48x48": "http://localhost:8081/secure/projectavatar?pid=10010&avatarId=10011" }, "issuetypes": [ { "expand": "fields", "self": "http://localhost:8081/rest/api/2/issuetype/1", "id": 1, "name": "Bug", "iconUrl": "http://localhost:8081/images/icons/bug.gif", "fields": { "summary": { "required": true, "schema": { "type": "string", "system": "summary" }, "operations": [ "set" ] }, "timetracking": { "required": false, "operations": [ ] }, "issuetype": { "required": true, "schema": { "type": "issuetype", "system": "issuetype" }, "operations": [ ], "allowedValues": [ { "id": "1", "name": "Bug", "description": "A problem which impairs or prevents the functions of the product.", "iconUrl": "http://localhost:8081/images/icons/bug.gif" } ] }, "customfield_10080": { "required": false, "schema": { "type": "array", "items": "string", "custom": "com.atlassian.jira.plugin.system.customfieldtypes:labels", "customId": 10080 }, "operations": [ ] }, . . . . "customfield_10010": { "required": false, "schema": { "type": "array", "items": "string", "custom": "com.atlassian.jira.plugin.system.customfieldtypes:labels", "customId": 10010 }, "operations": [ ] }, "customfield_10071": { "required": false, "schema": { "type": "array", "items": "string", "custom": "com.atlassian.jira.plugin.system.customfieldtypes:textfield", "customId": 10071 }, "operations": [ ] } } } ] } ] }
If you prefer, by omitting the projectKeys
and issuetypeNames
parameters you can retrieve all the issue
field data at once for all projects and issue types. However, this approach could amount to a very large response and could
take some time to build on systems with a large number of projects and issue types.
The Jira REST API allows you to discover the fields and data available and required for creating issues. For this, we use three different resources.
Examples in this section:
Discovering project
Discovering issue type data.
Discovering issue field data.
To create an issue in Jira, you first need to specify a project.
1 2http://localhost:8080/rest/api/2/project
1 2[ { "expand":"description,lead,url,projectKeys", "self":"http://localhost:8080/rest/api/2/project/10000", "id":"10000", "key":"TEST", "name":"Test", "avatarUrls":{ "48x48":"http://localhost:8080/secure/projectavatar?avatarId=10324", "24x24":"http://localhost:8080/secure/projectavatar?size=small&avatarId=10324", "16x16":"http://localhost:8080/secure/projectavatar?size=xsmall&avatarId=10324", "32x32":"http://localhost:8080/secure/projectavatar?size=medium&avatarId=10324" }, "projectTypeKey":"business" } ]
After selecting a project you will need an issue type. In Jira The Issue type together with the project is referred to as an Issue context and it is used to find the Jira schemes that control which fields are available for an issue, what the default values are, and which fields are mandatory.
Using the issue/createmeta/{projectIdOrKey}/issuetypes
resource you can discover the issue types under a project. The response will be paged.
1 2http://localhost:8080/rest/api/2/issue/createmeta/TEST/issuetypes?startAt=0&maxResults=50
1 2{ "maxResults":50, "startAt":0, "total":2, "isLast":true, "values":[ { "self":"http://localhost:8080/rest/api/2/issuetype/10000", "id":"10000", "description":"A task that needs to be done.", "iconUrl":"http://localhost:8080/secure/viewavatar?size=xsmall&avatarId=10318&avatarType=issuetype", "name":"Task", "subtask":false }, { "self":"http://localhost:8080/rest/api/2/issuetype/10001", "id":"10001", "description":"The sub-task of the issue", "iconUrl":"http://localhost:8080/secure/viewavatar?size=xsmall&avatarId=10316&avatarType=issuetype", "name":"Sub-task", "subtask":true } ] }
When you have the project and the issue type, you can retrieve the information for the issue fields by calling the /issue/createmeta/{projectIdOrKey}/issuetypes/{issueTypeId}
endpoint. The response will be paged.
1 2http://localhost:8080/rest/api/2/issue/createmeta/TEST/issuetypes/10000?startAt=0&maxResults=5
1 2{ "maxResults":5, "startAt":0, "total":11, "isLast":false, "values":[ { "required":false, "schema":{ "type":"user", "system":"assignee" }, "name":"Assignee", "fieldId":"assignee", "autoCompleteUrl":"http://localhost:8080/rest/api/latest/user/assignable/search?issueKey=null&username=", "hasDefaultValue":false, "operations":[ "set" ] }, { "required":false, "schema":{ "type":"array", "items":"attachment", "system":"attachment" }, "name":"Attachment", "fieldId":"attachment", "hasDefaultValue":false, "operations":[ ] }, { "required":false, "schema":{ "type":"string", "system":"description" }, "name":"Description", "fieldId":"description", "hasDefaultValue":false, "operations":[ "set" ] }, { "required":false, "schema":{ "type":"date", "system":"duedate" }, "name":"Due Date", "fieldId":"duedate", "hasDefaultValue":false, "operations":[ "set" ] }, { "required":true, "schema":{ "type":"issuetype", "system":"issuetype" }, "name":"Issue Type", "fieldId":"issuetype", "hasDefaultValue":false, "operations":[ ], "allowedValues":[ { "self":"http://localhost:8080/rest/api/2/issuetype/10000", "id":"10000", "description":"A task that needs to be done.", "iconUrl":"http://localhost:8080/secure/viewavatar?size=xsmall&avatarId=10318&avatarType=issuetype", "name":"Task", "subtask":false, "avatarId":10318 } ] } ] }
If you are building an integration that works across Jira versions (versions later and earlier than 8.4), you may want to check if the new endpoints are already available for your Jira instance. To do so, use one of the entries available in the the response of the /rest/capabilities endpoint.
Look for one of the capability names (list-project-issuetypes
or list-issuetype-fields
) in the response to determine if the new endpoints are present in the Jira instance.
To look for list-project-issuetypes
use:
1 2http://localhost:8080/jira/rest/api/2/issue/createmeta/{projectIdOrKey}/issuetypes?startAt=0&maxResults=50
or
To look for list-issuetype-fields
use:
1 2http://localhost:8080/jira/rest/api/2/issue/createmeta/{projectIdOrKey}/issuetypes/{issueTypeId}?startAt=0&maxResults=50
You can also parse these URLs and use them to make requests.
The examples in this section show you more advanced use cases for the REST API, like calling the REST API from a script or an app.
Examples in this section:
This example shows you how to write a small python script that will use REST interface to graph the relationships between issues in Jira site.
To simplify the REST requests, you can use the small helper library called restkit. This library is not strictly necessary – after all, REST is just an HTTP. However, restkit can be used for convenience. You also rely on pygraphviz to do the actual graphing for you too. To use it you will need Graphviz installed.
Using the Jira REST API is straightforward:
In the following example, 95% of the code is doing something other than interacting with the Jira REST API. So before you see the full example, let's highlight the actual REST usage out of context to show how simple it usually is. This example uses Python:
1 2resource = Resource(url + '/rest/api/2/issue/%s' % key, filters=[auth]) response = resource.get(headers = {'Content-Type' : 'application/json'}) if response.status_int == 200: # Not all resources will return 200 on success. There are other success status codes. Like 204. We've read # the documentation though and know what to expect here. issue = json.loads(response.body_string()) return issue else: return None
This performs a GET on the issue, checks for a successful response, and then parses the JSON response into a
Python dictionary.
The filters=\[auth\]
line is how you tell restkit to perform BASIC Authentication.
Later on, you'll reach into this Python dictionary to grab the data you want for your work.
1 2fields = issue['fields'] if fields.has_key('subtasks'): for subtask in issue['fields']['subtasks']: # do work with a subtask
You also get an Epic Link
custom field ID with following:
1 2def get_epic_id(url, key, auth): resource = Resource(url + ('/rest/api/latest/issue/%s?expand=names' % key), filters=[auth]) response = resource.get(headers={'Content-Type': 'application/json'}) if response.status_int == 200: for field_id, field_name in json.loads(response.body_string())['names'].items(): if field_name == 'Epic Link': return field_id else: return None
You can view the full source on Bitbucket.
You can see the script's command line options using the standard command:
1 2python draw-chart.py --help
You can test this against your Jira site with:
1 2python draw-chart.py --user=username --password=password --jira=<url-of-your-jira-site>
The output should look similar to:
1 2Fetching JRADEV-1391 Fetching JRADEV-2062 Fetching JRADEV-2063 Fetching JRADEV-1107 Fetching JRADEV-112 Fetching JRADEV-1108 Fetching JRADEV-1218 Fetching JRADEV-1219 Fetching JRADEV-1220 Fetching JRADEV-1221 Fetching JRADEV-1684 Fetching JRADEV-2064 Fetching JRADEV-1390 Fetching JRADEV-1389 Fetching JRADEV-1388 Fetching JRADEV-2125 Fetching JRADEV-1264 Fetching JRADEV-1256 Writing to issue_graph.png
Open the issue\_graph.png
to show an image that should look something like this:
Blue lines with arrows denote Sub-tasks.
This example shows you how to create a Jira app that uses the REST API. We want to look through all the comments on the issue and add a little tooltip that will pop-up when you hover over a link to a Jira issue.
The pop-up should contain a "quick view" of information about the target issue (similar to the example shown in the following image) so that you do not have to click the issue's link to see this information.
You can achieve this by using a Web Resource Context. This lets your app put JavaScript just on the View Issue page of Jira.
Define the Web Resource Context in the atlassian-plugin.xml
file:
1 2<web-resource key="remote-link" name="Remote Issue Linking"> <dependency>com.atlassian.auiplugin:ajs</dependency> <resource name="java-demo-plugin.js" type="download" location="js/java-demo-plugin.js"/> <context>jira.view.issue</context> </web-resource>
Have java-demo-plugin.js
look in the comment body for URLs that "look like" they might point to Jira issues.
Obtain the JSON representation of the issue using Jira's REST API, do some quick formatting on it, and put it into an AUI InlineDialog.
1 2define('issue-hover', ['ajs'], function(AJS){ AJS.toInit(function() { var i = new Date().getTime(); AJS.$("#issue_actions_container").find('.action-body a').each(function() { if (this.href.match(/\/browse\/[A-Z]+\-\d+$/)) { var split = this.href.split('/browse/'); var base = split[0]; var key = split[1]; var options = { cacheContent: true, onHover: true, showDelay: 400, hideDelay: 400, closeOthers: false, width: 500 } var draw = function(contents, trigger, showPopup) { AJS.$.getJSON(base + '/rest/api/latest/issue/' + key, function(data) { var fields = data["fields"]; contents.empty(); contents.append( "<ul class=\"item-details\">" + "<li>" + "<dl><dt>Summary: </dt>" + "<dd>" + fields["summary"] + "</dd></dl>" + "<dl><dt>Type: </dt>" + "<dd>" + fields["issuetype"]["name"] + "</dd></dl>" + "<dl><dt>Priority: </dt>" + "<dd>" + fields["priority"]["name"] + "</dd></dl>" + "<dl><dt>Status: </dt>" + "<dd>" + fields["status"]["name"] + "</dd></dl>" + "<dl><dt>Assignee: </dt>" + "<dd>" + fields["assignee"]["name"] + "</dd></dl>" + "<dl><dt>Description: </dt>" + "<dd>" + fields["description"] + "</dd></dl>" + "</li></ul>"); contents.append("<form id=\"add-watch\" name=\"watch\" action=\"\">"); AJS.$("<input type=\"button\" name=\"button\" value=\"Watch\"/>").click(function() { // We don't actually know our own username...and we need it to add a Watcher. So we get it from the // "current user" resource AJS.$.getJSON(base + '/rest/auth/latest/session', function(data) { AJS.$.ajax({ type: "POST", url: base + "/rest/api/latest/issue/" + key + "/watchers", data: "\""+ data['name']+ "\"", dataType: "json", contentType: "application/json" }) }) }).appendTo(contents); contents.append("</form>"); showPopup() }) }; AJS.InlineDialog(AJS.$(this), "issue-linking-" + (i++), draw, options) } }) }) }); require('issue-hover');
You can view the full demo app on Bitbucket.
Rate this page: