Is it possible to get the issue history using the REST API?

Angel Montenegro June 24, 2012

Is it possible to get the history of an issue using the JIRA REST API?

Thanks.

11 answers

1 accepted

7 votes
Answer accepted
Stefan Kohler
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
June 24, 2012

Depending on the kind of history you're looking for this is possible.

http://docs.atlassian.com/jira/REST/latest/#id162178

Another great way to discover the JIRA rest api is via the rest api browser, which is included in the developers toolbox or a JIRA development:

- https://developer.atlassian.com/display/RAB/Overview+of+the+Atlassian+REST+API+Browser
- https://marketplace.atlassian.com/plugins/com.atlassian.devrel.developer-toolbox-plugin

Cheers

bradley.shields@datadoghq.com December 4, 2020

Definitely add ?expand=changelog as Jonny Xu added below, I didn't see column changes without it!

35 votes
Chris Young November 25, 2012

Jonny, that is fantastic. It works! Many Thanks.

jira = JIRA(options, basic_auth=(USERNAME, PASSWORD))

issue = jira.issue('FOO-100', expand='changelog')
changelog = issue.changelog

for history in changelog.histories:
    for item in history.items:
        if item.field == 'status':
            print 'Date:' + history.created + ' From:' + item.fromString + ' To:' + item.toString

Gives me:

Date:2012-10-23T09:49:41.197+0100 From:Open To:Queued
Date:2012-10-23T09:49:43.838+0100 From:Queued To:In Progress
Date:2012-10-23T09:49:45.390+0100 From:In Progress To:Blocked
Date:2012-10-29T16:06:36.733+0000 From:Blocked To:In Progress
Date:2012-10-31T16:47:40.191+0000 From:In Progress To:Peer Review
Date:2012-10-31T16:47:41.783+0000 From:Peer Review To:Customer Approval

Which is exactly what I wanted!

Now I can get data on cycle time, figure out where our bottlenecks are and see which tickets are dropping out of our workflow after we have commited to working on them.

Brilliant.

Many Thanks!

Oleksandr December 18, 2015

Hello Chris, could you tell me how can i get status of field "assignee" from someone to someone? and how can i get comment from jira?

Chai Teng Ong August 22, 2017

Hi Chris, can I have a sample of code in Excel VBA format?

Like MANUEL Perez Breva likes this
Ventsislav January 31, 2020

Here are all possible item types:

item_fields = {
'Epic Link',
'Link',
'Notes for QA',
'Rank',
'WorklogId',
'assignee',
'description',
'status',
'summary',
'timeestimate',
'timespent'
}
Like Biplab Roy likes this
7 votes
Deleted user November 25, 2012

Hi Chris, i think this is what you are looking for

https://jira.atlassian.com/browse/JRA-27692?focusedCommentId=303842&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-303842

https://jira.atlassian.com/rest/api/2/issue/JRA-22053?expand=changelog

In that example, you can see that one of the top-level attributes is "expand", and it includes the expandable name "changelog". If you add<tt>?expand=changelog</tt> then JIRA will include the changelog (issue history) in the response.

bradley.shields@datadoghq.com December 4, 2020

Doing God's work here, thank you so much for this 

Minglei Liu
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
January 9, 2024

it works for me, at 2024, so much appreciate

Like Tejas Katariya likes this
1 vote
Matt Doar August 25, 2013

I had to use getattr(item, 'from') instead of item.from due to reserved keywords in Python

1 vote
Chris Young October 28, 2012

I would like to get the change history for an issue, i.e. the information shown on an issue's 'History' tab:

Jira Ticket History Tab

I have tried to do this using the Python wrapper to the REST API as follows:

from jira.client import JIRA
import json

options = {
    'server': 'https://yada-yada.atlassian.net',
}

jira = JIRA(options, basic_auth=(USERNAME, PASSWORD))

projects = jira.projects()
issue = jira.issue('INF-119')
print json.dumps(issue.raw)

The result is this:

{
    "key": "INF-119",
    "fields": {
        "comment": {
            "total": 0,
            "startAt": 0,
            "comments": [],
            "maxResults": 0
        },
        "customfield_10700": null,
        "customfield_10703": null,
        "customfield_10702": null,
        "customfield_10705": null,
        "customfield_10704": null,
        "customfield_10600": null,
        "customfield_10601": null,
        "labels": [],
        "aggregatetimespent": null,
        "watches": {
            "self": "https://yada-yada.atlassian.net/rest/api/2/issue/INF-119/watchers",
            "watchCount": 1,
            "isWatching": false
        },
        "assignee": {
            "displayName": "Chris Young",
            "name": "chris.young",
            "self": "https://yada-yada.atlassian.net/rest/api/2/user?username=chris.young",
            "avatarUrls": {
                "48x48": "https://yada-yada.atlassian.net/secure/useravatar?ownerId=chris.young&amp;avatarId=10300",
                "16x16": "https://yada-yada.atlassian.net/secure/useravatar?size=small&amp;ownerId=chris.young&amp;avatarId=10300"
            },
            "emailAddress": "Chris.Young@yada-yada.com",
            "active": true
        },
        "lastViewed": null,
        "issuelinks": [],
        "worklog": {
            "worklogs": [],
            "total": 0,
            "startAt": 0,
            "maxResults": 0
        },
        "customfield_10400": null,
        "aggregateprogress": {
            "progress": 0,
            "total": 0
        },
        "environment": null,
        "votes": {
            "hasVoted": false,
            "self": "https://yada-yada.atlassian.net/rest/api/2/issue/INF-119/votes",
            "votes": 0
        },
        "fixVersions": [],
        "priority": {
            "iconUrl": "https://yada-yada.atlassian.net/images/icons/priority_critical.gif",
            "self": "https://yada-yada.atlassian.net/rest/api/2/priority/2",
            "name": "Critical",
            "id": "2"
        },
        "timespent": null,
        "customfield_10109": null,
        "aggregatetimeestimate": null,
        "progress": {
            "progress": 0,
            "total": 0
        },
        "duedate": null,
        "attachment": [],
        "status": {
            "id": "6",
            "iconUrl": "https://yada-yada.atlassian.net/images/icons/status_closed.gif",
            "self": "https://yada-yada.atlassian.net/rest/api/2/status/6",
            "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.",
            "name": "Closed"
        },
        "updated": "2012-10-29T13:53:58.317+0000",
        "customfield_10200": [],
        "subtasks": [],
        "description": null,
        "reporter": {
            "displayName": "Chris Young",
            "name": "chris.young",
            "self": "https://yada-yada.atlassian.net/rest/api/2/user?username=chris.young",
            "avatarUrls": {
                "48x48": "https://yada-yada.atlassian.net/secure/useravatar?ownerId=chris.young&amp;avatarId=10300",
                "16x16": "https://yada-yada.atlassian.net/secure/useravatar?size=small&amp;ownerId=chris.young&amp;avatarId=10300"
            },
            "emailAddress": "Chris.Young@yada-yada.com",
            "active": true
        },
        "customfield_10103": null,
        "customfield_10102": null,
        "customfield_10101": null,
        "customfield_10100": "3_*:*_1_*:*_4111_*|*_1_*:*_1_*:*_10925_*|*_6_*:*_1_*:*_0_*|*_10011_*:*_1_*:*_4469_*|*_10013_*:*_1_*:*_2206_*|*_10009_*:*_1_*:*_2121",
        "timeestimate": null,
        "timeoriginalestimate": null,
        "customfield_10000": "3659",
        "aggregatetimeoriginalestimate": null,
        "customfield_10300": "3656",
        "customfield_10701": null,
        "created": "2012-10-29T13:53:34.485+0000",
        "versions": [],
        "resolutiondate": "2012-10-29T13:53:58.306+0000",
        "summary": "Dummy ticket to see if we can extract change history",
        "project": {
            "self": "https://yada-yada.atlassian.net/rest/api/2/project/INF",
            "avatarUrls": {
                "48x48": "https://yada-yada.atlassian.net/secure/projectavatar?pid=10200&amp;avatarId=10010",
                "16x16": "https://yada-yada.atlassian.net/secure/projectavatar?size=small&amp;pid=10200&amp;avatarId=10010"
            },
            "id": "10200",
            "key": "INF",
            "name": "Infrastructure"
        },
        "timetracking": {},
        "components": [],
        "issuetype": {
            "name": "Infrastructure",
            "self": "https://yada-yada.atlassian.net/rest/api/2/issuetype/9",
            "iconUrl": "https://yada-yada.atlassian.net/images/icons/genericissue.gif",
            "subtask": false,
            "id": "9",
            "description": "Things that the team will need to spend time working on but which don't actually deliver any value."
        },
        "resolution": {
            "self": "https://yada-yada.atlassian.net/rest/api/2/resolution/1",
            "id": "1",
            "name": "Fixed",
            "description": "A fix for this issue is checked into the tree and tested."
        },
        "workratio": -1
    },
    "self": "https://yada-yada.atlassian.net/rest/api/2/issue/15913",
    "id": "15913",
    "expand": "renderedFields,names,schema,transitions,operations,editmeta,changelog"
}

So, unless I'm missing something it looks like you cannot access an issue's history via the REST API.

My work around is to screen scrape this information via selenium.

Before I go down this path can someone tell me if I am missing a trick and there is a less brittle / time consuming way of doing this?

I am using the hosted JIRA fo which AFAIK the only API access is via REST.

Thanks

Chris

1 vote
Jobin Kuruvilla [Adaptavist]
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
June 24, 2012

Nope. You can find available methods here: http://docs.atlassian.com/jira/REST/latest/

0 votes
Théo Fleury September 26, 2020

Hello, in PowerShell I created this function :


function Get-JiraIssueChangelog {

Param (
[Parameter(Mandatory)]
$Issue,
[Parameter(Mandatory)]
$Server,
[Parameter(Mandatory)]
$Headers
)
#https://community.atlassian.com/t5/Jira-questions/Is-it-possible-to-get-the-issue-history-using-the-REST-API/qaq-p/510094

<#

$uri = “https://xxx.atlassian.net/rest/api/latest/issue/YYYY-100/changelog?startAt=0&maxResults=100”
$projectIssuePage = Invoke-RestMethod $uri -Method ‘GET’ -Headers $headers
$projectIssuePage

#>

try {
return (Invoke-RestMethod -Method Get -Uri "$Server/rest/api/2/search?jql=key=$Issue&expand=changelog" -Headers $Headers).issues.changelog.histories;
#Invoke-RestMethod -Method Get -Uri "$Server/rest/api/latest/issue/$Issue/changelog?startAt=0&maxResults=100” -Headers $Headers;

}
catch {
$_
}
}

function Get-JiraIssueTransition {

Param (
[Parameter(Mandatory)]
$Issue,
[Parameter(Mandatory)]
$Server,
[Parameter(Mandatory)]
$Headers
)

$object_Histories = Get-JiraIssueChangelog -Issue $Issue -Server $Server -Headers $Headers;

$object_Transitions = @();

foreach ($object_History in $object_Histories){
foreach($object_item in $object_History.items){
if($object_item.field -EQ 'status')
{
$object_Transitions += [pscustomobject]@{
author = $object_History.author.name
date = (Get-Date $object_History.created)
to = $object_item.toString
from = $object_item.fromString
}
}
}
}

return $object_Transitions;
}

Johannes Spangenberg November 23, 2020

The endpoint

/rest/api/latest/issue/YYYY-100/changelog

does not exist on my instance. Maybe it was introduces in a later version. However, I also cannot find this endpoint in the latest documentation.

Jira 8.13.1 (atlassian.com)

Where did you find this endpoint?

0 votes
MattS
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
August 26, 2013

Interestingly there is an expand parameter for the search method, so it ought to be possible to retrieve issues with the changelog directly from a search. At the moment with jira-python I'm still having to do a second call such as

issue = jira.issue('FOO-100', expand='changelog')

It would be great to avoid the second network round trip, but performance was not as bad as I thought. I ended up running a search, getting the changelog for each issue and updating the reporter at a rate of about one issue per second.

0 votes
VIKAS KUMAR May 16, 2013

Hi Chris,

Can you please post your full code so that i can have a better exposer of REST, since i am a new user to it.

It will be really helpfull for my work experience with JIRA.

I am working on same task to retrieve Issue History with a Jira ticket.

Thanks !

0 votes
Dieter Arand November 27, 2012

OK, I guess I found the problem.

We are using Jira 4.3.3 and it looks like, that this interface is not supported for that version.

Also '?fields' does not work.

So any other idea how I can get the change history for an item or can get access to single fields with my version?

0 votes
Dieter Arand November 27, 2012

Hi,

I'm using the REST interface in Excel with VBA.

I know that expand=changelog should do the job, but I get the same result either with this expresson or without it.

I attached my test code and both DEebig.Print deliver exactly the same result

Any idea what's wrong?

Many Thanks!

Dieter

Private JiraService As New MSXML2.XMLHTTP60
Private JiraAuth As New MSXML2.XMLHTTP60
Public sRestAntwort As String

Sub JiraAccess()
With JiraAuth
    .Open "POST", "http://JiraServer/rest/auth/1/session", False
    .setRequestHeader "Content-Type", "application/json"
    .setRequestHeader "Accept", "application/json"
    .Send " {""username"" : ""user"", ""password"" : ""passwd""}"""
    sCookie = "JSESSIONID=" &amp; Mid(sErg, 42, 32) &amp; "; Path=/Jira"
End With

With JiraService
    .Open "GET", "http://JiraServer/rest/api/2.0.alpha1/issue/JRA-444", False
    .setRequestHeader "Content-Type", "application/json"
    .setRequestHeader "Accept", "application/json"
    .setRequestHeader "Set-Cookie", sCookie
    .Send
    sRestAntwort = .responseText
    Debug.Print "*************************"
    Debug.Print .responseText
    Debug.Print "*************************"
End With

With JiraService
    .Open "GET", "http://JiraServer/rest/api/2.0.alpha1/issue/JRA-444?expand=changelog", False
    .setRequestHeader "Content-Type", "application/json"
    .setRequestHeader "Accept", "application/json"
    .setRequestHeader "Set-Cookie", sCookie
    .Send
    sRestAntwort = .responseText
    Debug.Print "*************************"
    Debug.Print .responseText
    Debug.Print "*************************"
End With

With JiraAuth
    .Open "DELETE", "http://JiraServer/rest/auth/1/session", False
    .Send
End With
End Sub

Suggest an answer

Log in or Sign up to answer