Library / SDK
atlassian-api/atlassian-python-api avatar
atlassian-api/atlassian-python-api

atlassian-python-api and the Cloud token trap in token=

Atlassian Python REST API wrapper. The atlassian-python-api library provides a simple and convenient way to interact with Atlassian products (such as Jira Service management, Jira Software, Confluence, Bitbucket and apps Insight, X-Ray) using Python. It is based on the official REST APIs of these products and by community for Atlassian

1,680 stars715 forksPythonApache-2.0

At a glance

What is it?
atlassian-python-api wraps the Jira, Confluence, Bitbucket, Bamboo, Insight and X-Ray REST endpoints in one Python package with per product classes. Its sharpest edge is authentication: a Server personal access token and a Cloud API token go into different arguments and go wrong in a specific way.
Who is it for?
Adopt atlassian-python-api if your Python code has to talk to several Atlassian products and you want one import and one session object instead of hand written requests calls. Do not adopt it for a single endpoint, where requests itself is less to maintain, and do not treat it as an Atlassian supported client, since it tracks private methods as well as documented ones.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One package, one class per Atlassian product

atlassian-python-api is a wrapper over the REST APIs of Atlassian products, and the design is straightforward: one class per product, imported from the top level `atlassian` package. `Confluence`, `Jira` and `ConfluenceV2` appear throughout the README, and the repository carries an `atlassian/` package whose topic tags list the products covered: Jira, Jira Service Desk, Confluence, Bitbucket, Bamboo, Crowd, Insight, X-Ray, Portfolio, Tempo and assets.

What sits underneath is not only the documented REST surface. The README states the library is based on the official REST APIs plus additional private methods and protocols, naming xml+rpc and raw HTTP requests as examples. That is a design choice with consequences: methods exist that Atlassian does not document and may change without notice, so a pinned version can break under you when a private endpoint moves. Public API changes rarely do that, so the risk is concentrated in a minority of methods.

The package targets both deployment models. It says it is compatible with Atlassian Server and Cloud instances, and the code carries a `cloud=True` flag on the constructors that switches path and authentication behaviour. `setup.py` declares `python_requires='>=3.9'` and `platforms="Platform Independent"`, and it ships the runtime dependencies inline: beautifulsoup4, deprecated, jmespath, oauthlib, requests, requests_oauthlib and typing-extensions. Kerberos support is optional through the `kerberos` extra, which pulls in requests-kerberos.

The examples directory is organised per product, with subfolders for bamboo, bitbucket, cloud_admin, confluence, crowd, insight, jira and xray, plus a set of flat Confluence V2 scripts covering comments, content types, labels, page properties, tasks and whiteboard custom content. That layout is the fastest way to find the pattern for the endpoint you need.

The one mistake that produces 403 Failed to parse Connect Session Auth Token

Authentication is where most of the friction sits, and the README documents it more precisely than most wrappers do.

There are two token kinds. A Jira or Confluence Server or Data Center personal access token goes into `token=` and is sent as a Bearer token:

python
from atlassian import Confluence, Jira

confluence = Confluence("https://confluence.company.example", token="server-or-dc-pat")
jira = Jira("https://jira.company.example", token="server-or-dc-pat")

An Atlassian Cloud API token is the opposite. It goes into HTTP Basic authentication, with the account email as `username` and the token as `password`, plus `cloud=True`:

python
from atlassian import Confluence, Jira

confluence = Confluence(
    "https://your-domain.atlassian.net",
    username="[email protected]",
    password="cloud-api-token",
    cloud=True,
    timeout=120,  # Optional; useful on slow/VPN connections.
)
spaces = confluence.get_all_spaces()

Passing a Cloud API token to `token=` is the documented failure. The library builds a Bearer header, and Cloud commonly answers with `403 Failed to parse Connect Session Auth Token`. The message names a Connect Session layer that has nothing to do with your token, which is what makes it confusing to debug. Note also that you must not base64-encode the credentials yourself, since `requests` encodes the required `email:api_token` Basic credentials automatically.

For Confluence Cloud there is a third path, and it comes with a URL rule. You use the site URL without a trailing `/wiki`, because the client adds the required API context. Either instantiate the dedicated class:

python
from atlassian import ConfluenceV2

confluence_v2 = ConfluenceV2(
    "https://your-domain.atlassian.net",
    username="[email protected]",
    password="cloud-api-token",
)
page = confluence_v2.get_page_by_id("123456789", body_format="storage")
storage_xhtml = page["body"]["storage"]["value"]

Or keep the `Confluence` class and pass `api_version=2` together with `cloud=True`. The README shows both forms producing the same page read. `ConfluenceV2` needs no `cloud=True` flag because it is an explicit Cloud V2 client.

jql is deprecated on Cloud, so use enhanced_jql and nextPageToken

The traditional Jira query method is deprecated, and the reason is Atlassian's pagination change rather than anything the library chose.

The classic call still works against older deployments:

python
from atlassian import Jira
import requests

session = requests.Session()
jira = Jira(
    url='https://your-jira-instance.atlassian.net',
    username='[email protected]',
    password='your-api-token',
    cloud=True,  # Ensure this is set to True for Jira Cloud
    session=session  # Optional: use a session for persistent connections
)
JQL = 'project = DEMO AND status IN ("To Do", "In Progress") ORDER BY issuekey'
data = jira.enhanced_jql(JQL)
print(data)

The README states that `jql` is deprecated for Jira Cloud users because Atlassian has moved from `startAt` based pagination to a `nextPageToken` based approach, and it recommends `enhanced_jql` for performance and forward compatibility. The practical consequence for your code is that a `startAt` loop you wrote against `jql` has no equivalent assumption left on Cloud, so paging logic written before the migration is worth reviewing before you rely on it.

Both constructors accept a `requests.Session`, which is the other thing worth doing. Passing a session keeps connections alive across many calls and lets you set pool sizing once. If you are pulling a large backlog with `enhanced_jql`, that is the difference between a fast script and a slow one.

pip install atlassian-python-api, then run the QA container to work on it

Installation is a single command from PyPI:

bash
pip install atlassian-python-api

From source, the README gives two routes: clone the repository then `pip install -r requirements.txt` for the runtime packages, or `pipenv install && pipenv install --dev` for a managed environment.

The version number is not in a config file you can read. `setup.py` opens `atlassian/VERSION` and reads it, so the version lives in the package tree. `setup.py` is also still the packaging authority even though the repository carries a `pyproject.toml`, because the version and the dependency list are defined in the setup script.

For development the Makefile is the interface. `make help` lists the tasks, and `make setup-dev` upgrades pip and pytest then installs `requirements-dev.txt`. `make qa` and `make tox` run the same thing through tox with `PYTHONDONTWRITEBYTECODE=1`. `make docker-qa` builds a container image and runs the suite in it, mounting the working tree at `/atlassian-python-api`, and `make docker-fmt` runs the `black_fmt` tox environment. The image tag defaults to `atlassian-python-api-qa-$(PYTHON_VERSION)` with `PYTHON_VERSION` defaulting to 3.9, and `TEST_OPTS` is passed through to pytest.

Formatting is fixed at a line length of 120 with `black` targeting py310, py311 and py312, and pylint is configured with `fail-under = '10.0'`. If you send a patch, that line length is the first thing that will bite you.

Real limits: private endpoints, a Beta label and a conflicting dependency list

Three caveats deserve to be stated plainly.

First, the wrapper covers private and undocumented Atlassian methods alongside the official ones. That is what makes it broad, and it is also why a Server to Cloud move can break a method you did not know was private.

Second, `setup.py` classifies the package as `Development Status :: 4 - Beta`, which sits below the stable label. The README calls itself well documented and actively maintained, and the repository is not archived with a last push on 2026-10-03, so the code is moving. The release history shows three tags in about two months: 5.0.3 on 2026-08-17, 5.0.4 on 2026-08-28 with a Confluence API method fix and a new Company Calendar API, and 5.0.5 on 2026-09-15 with Confluence Server and Jira Server bugfixes. Two of those three are about Server compatibility, which is the area most sensitive to Atlassian product changes.

Third, the dependency files disagree. `setup.py` declares the install set, while the root `requirements.txt` is annotated and lists `requests>=2.8.1`, oauthlib, requests-oauthlib, `requests-kerberos==0.14.0`, typing-extensions, jmespath, beautifulsoup4 and urllib3. That file pins Kerberos exactly and does not mention `deprecated` or `typing-extensions` at the versions `setup.py` asks for. Install from PyPI and let `setup.py` resolve; treat the root file as a developer convenience list.

One more naming trap: `ConfluenceV2` and `Confluence(api_version=2)` both reach the V2 API, but a V2 page read returns a nested `body.storage.value` dict, not a plain string. Code written against the old shape will find an extra dict layer.

How it compares with raw requests and with Atlassian's own clients

The obvious alternative is to skip the wrapper. A `requests.Session` with the Atlassian REST base URL and a Basic auth header is about six lines, and it gives you exactly the endpoint semantics with nothing in between. For one or two calls, that is the better trade, and you avoid the compatibility surface the wrapper adds.

The wrapper wins on coverage. When your script touches Confluence, Jira, Bitbucket, X-Ray and Insight, the difference is that the wrapper has already resolved each product's base path, auth style, Cloud flag and pagination differences, and gives you one session you can share. Hand rolling that for five products means maintaining five authentication variants, which is exactly the class of bug the `token=` versus `password=` problem above represents.

If your only need is documented endpoints, that is a defensible choice.

Editorial conclusion

Adopt atlassian-python-api if your Python code has to talk to several Atlassian products and you want one import and one session object instead of hand written requests calls. Do not adopt it for a single endpoint, where requests itself is less to maintain, and do not treat it as an Atlassian supported client, since it tracks private methods as well as documented ones. Verify first which side of your deployment you point at: on Cloud use username= and password= with cloud=True, and only put a Server or Data Center personal access token in token=.

Frequently asked questions

How do I install atlassian-python-api?

Run pip install atlassian-python-api from PyPI, or clone the repository and use pip install -r requirements.txt, or pipenv install && pipenv install --dev for a managed environment. Python 3.9 or newer is required.

Why do I get 403 Failed to parse Connect Session Auth Token in atlassian-python-api?

Because an Atlassian Cloud API token was passed to token=, which builds a Bearer header, while Cloud expects HTTP Basic authentication. Pass the account email as username= and the API token as password= together with cloud=True, and let requests do the base64 encoding.

What is the difference between jql and enhanced_jql in atlassian-python-api?

The traditional jql method is deprecated for Jira Cloud users because Atlassian moved from startAt to nextPageToken based pagination. The README recommends enhanced_jql for improved performance and future compatibility.

How do I read a Confluence Cloud page with the v2 API in atlassian-python-api?

Use the ConfluenceV2 class, or pass api_version=2 with cloud=True to Confluence, and give the site URL without a trailing /wiki. Call get_page_by_id with body_format="storage" and read page["body"]["storage"]["value"].

Does atlassian-python-api work with Jira Server or Data Center?

Yes. It states compatibility with both Atlassian Server and Cloud instances, and a Server or Data Center personal access token is passed as token= and sent as a Bearer token.

Official sources

  1. atlassian-api/atlassian-python-api on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/atlassian-api-atlassian-python-api.svg)](https://hysenlabs.com/projects/atlassian-api-atlassian-python-api)

Was this useful?