Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

How to use the new Jira cloud issue search API

If you're anything like me, you enjoy pushing boundaries—testing things just to see if they break or lead to something unexpected. But let’s get to the real reason I’m writing this article. If you manage Jira or work with API's in your organization, you’ve probably noticed changes in the Jira Issue Search API.

Now, if you’ve been keeping up with Atlassian’s developer changelogs, this won’t be news. But regardless of whether you were following or not, the bottom line is: the API is changing, and that means some things will break. I’m talking about those scripts, automations, or little tools you wrote ages ago and forgot about, which quietly keep your systems running.

While this change might cause some headaches, it’s not all bad news. In fact, the old API had its issues. It pulled large amounts of data with little control, forcing you to parse unnecessary information. The new API, on the other hand, lets you request only the fields you need. This makes responses smaller, faster, and easier on memory.

However, not everything is smooth sailing. For instance, the startAt parameter is gone. It’s been replaced by nextPageToken, which actually improves performance—but it does mean rewriting parts of your code.

As someone who builds and maintains automation around Jira, I’ve already adapted to this with my Python library, jiraone. If you’ve seen my previous posts, you’ll know this library supports tasks like exporting issues, getting changelogs, calculating time-in-status, and more—all of which used the old issue search API.

With version v0.8.7, I introduced support for the new API, making it easier for admins and developers to transition without losing much functionality.

Basic Usage

Here's how you can use the new API with jiraone. See the docs for more information about the arguments you can use.

Example: Simple GET Request

# previous import statement  
resp = LOGIN.get(endpoint.search_cloud_issues(
query='project = AT',
fields=None,)
)

if resp.status_code < 300:
data = resp.json()

print(data)

# {["issues": [...]]}

The reason I used fields=None is that I don't want to return all field data. You can specify what field you want returned by typing a string of the field name separated by a comma. If the argument is removed, by default, all fields are returned, which will be a large payload to parse. The query argument expects any valid JQL and requires a bounded query, which means you have to specify exact search restrictions; otherwise, it won't work.

Example: POST Request (for larger queries)

# previous import statement  
resp = LOGIN.post(endpoint.search_cloud_issues(
query='project = AT',
method="post",
fields=None,
), payload=endpoint.get_issue_search_payload)

if resp.status_code < 300:
data = resp.json()

print(data)

# {["issues": [...]]}

Notice that you don’t need to create a payload, but what happens here is that by defining the arguments you want, it is automatically added as an object when you call endpoint.get_issue_search_payload and assign it as a value to the payload argument of LOGIN.post

To handle pagination (since results may span multiple pages), you need to loop using the nextPageToken:

# previous expressions 
if resp.status_code < 300:
data = resp.json()


while "nextPageToken" in data:

if "issues" in data:

# the issues will be a list which you can loop

issues = data.get("issues")

# you can attach the issues data to another object

# or process it the way you see fit

resp = LOGIN.get(endpoint.search_cloud_issues(
query='project = AT',
fields=None,
next_page=data.get("nextPageToken")
))
if resp.status_code < 300:

data = resp.json()

Enhanced Function: enhance_search

To simplify pagination, I added the enhance_search function in the jiraone.utils module. It automatically handles paging and returns all results with a total count of how many issues it's returning. For those of you thinking of making multiple APIs, this handles that request quite nicely.

GET Example

# previous import statement  
from jiraone.utils import enhance_search

data = enhance_search(endpoint.search_cloud_issues(
query='project = AT', fields=None,
) )
print(data)
# {["total": 287, "issues": [...]]}

POST Example

# previous import statement  
from jiraone.utils import enhance_search

data = enhance_search(endpoint.search_cloud_issues(
query='project = AT',
method="post",
fields=None,),
method="post" )
print(data)
# {["total": 287, "issues": [...]]}

Note: Both search_cloud_issues and enhance_search take a method argument. If using POST, you must set "post" in both places.

Putting It All Together

Here’s a quick example using a config file and script: config.json

{ "user": "myuser@example.com", 
"password": "MY_API_TOKEN",
"url": "https://yoursite.atlassian.net"
}

Python file, e.g. myscript.py

from jiraone import endpoint, LOGIN 
from jiraone.utils import enhance_search
import json

file = "config.json"
config = json.load(open(file))
LOGIN(**config)

data = enhance_search(endpoint.search_cloud_issues(
query='project = AT',
method="post",
fields=None,
), method="post"
)
print(data)
# {["total": 287, "issues": [...]]}

If you’re using Jira DC, you can continue using the older endpoint.search_issues_jql.


This change may be disruptive in the short term, but it opens the door to more efficient, flexible scripting. Hopefully, this article helps you adapt your tools and keep your Jira automations running smoothly.

2 comments

Erick Miranda Márquez
Contributor
April 24, 2025

Great explanation! Thanks a lot. 🏆

Michiel Schuijer
Contributor
April 29, 2025

Excellent article, thanks!

Comment

Log in or Sign up to comment
TAGS
AUG Leaders

Atlassian Community Events