Skip to main content

jira2py

PyPI version Python versions License: MIT

A type-safe Python client for the Jira Cloud REST API v3. Use it to read and search issues, create and edit issues, transition workflows, retrieve changelogs, discover canonical field IDs, and work with comments, attachments, links, worklogs, projects, metadata, users, and saved filters.

Scope

jira2py supports Jira Cloud and Python 3.11+. It does not support Jira Server or Data Center, board/sprint/epic workflows, issue deletion or archiving, or a dedicated issue-assignment API.

Install

pip install jira2py

Authenticate safely

Create an Atlassian API token, then provide your Cloud URL, Atlassian account email, and token. Without credentials_file, each credential uses a non-empty explicit url, username, or api_token argument, then its JIRA_URL, JIRA_USER, or JIRA_API_TOKEN environment variable.

When you supply credentials_file, jira2py first loads and validates it as a complete set: the JSON must contain non-empty url, username, and api_token values. A partial file cannot be completed from explicit arguments or environment variables; after validation, non-empty explicit arguments override their matching file values.

There is no default credentials-file path. Keep tokens out of source control, logs, and error reports; use environment variables or a protected local JSON file instead.

export JIRA_URL="https://your-domain.atlassian.net"
export JIRA_USER="your-email@example.com"
export JIRA_API_TOKEN="your-api-token"
{
  "url": "https://your-domain.atlassian.net",
  "username": "your-email@example.com",
  "api_token": "your-api-token"
}

Pass the JSON file only when needed:

from jira2py import JiraAPI

jira = JiraAPI(credentials_file="./jira-credentials.json")

Choose an API layer

  • JiraAPI is the low-level, endpoint-oriented interface. Operations return parsed Jira JSON-like data when available; downloads return bytes and operations without a response body return None.
  • JiraHelpers provides grouped workflows and readable HelperResult values, with optional structured data, for common tasks.
  • format_issue is an optional pure presentation function for an issue response you already retrieved.

Use JiraAPI when you want direct REST payloads and endpoint control. Full issue retrieval is performed only by jira.issues.get_issue():

from jira2py import JiraAPI

jira = JiraAPI()
issue = jira.issues.get_issue("PROJECT-123", fields=["summary", "status"])
results = jira.search.enhanced_search("project = PROJECT AND status = 'In Progress'")

Use format_issue only when you want readable text in addition to that structured response. It does not fetch data or change the response:

from jira2py import JiraAPI
from jira2py.helpers import JiraHelpers, format_issue

api = JiraAPI()
issue = api.issues.get_issue(
    "PROJECT-123",
    fields=["summary", "status", "description"],
)
print(format_issue(issue, browse_url=f"{api.credentials.url}/browse/{issue['key']}"))

helpers = JiraHelpers(api)
print(helpers.metadata.transitions("PROJECT-123").text)
field_page = helpers.metadata.list_fields("PROJECT", field_types=["custom"])
print(field_page.text)  # names plus canonical IDs; one Jira page
print(helpers.attachments.list("PROJECT-123").text)
print(helpers.changelogs.list("PROJECT-123").text)

Structured issue-read migration

Issue reads no longer use a helper or a comma-delimited fields string. Pass one exact selector per sequence item, then optionally format the returned data:

# Before (removed)
from jira2py.helpers import JiraHelpers

helpers = JiraHelpers(api)
api.issues.get_issue("PROJECT-123", fields="summary,status")
helpers.issues.read("PROJECT-123", extra_fields=["customfield_10001"])

# After
issue = api.issues.get_issue(
    "PROJECT-123",
    fields=["summary", "status", "customfield_10001"],
)
text = format_issue(
    issue,
    browse_url=f"{api.credentials.url}/browse/{issue['key']}",
)

The supplied selector sequence is forwarded unchanged: jira2py does not add fields, deduplicate selectors, or request an expansion. None omits fields and lets Jira choose its default unless raw extra_params["fields"] overrides it. Wildcards and negative selectors such as "*all" and "-description" can still return broad responses; choose projections deliberately.

Jira account mentions in high-level Markdown

High-level Markdown write helpers recognize Jira account mentions in the canonical form [~accountId:<account-id>]. Use a real opaque account ID from Jira user discovery, not a display name:

helpers.comments.add("PROJECT-123", "Please review: [~accountId:557057:User:AbC]")

This applies to issue create/edit descriptions, environment, compatible custom textarea fields, comment add/update bodies, and worklog add/update comments. The accountId label is case-insensitive on input, and IDs can contain :. A single leading backslash escapes a token; malformed tokens and tokens inside Markdown code, links, or images remain ordinary text rather than creating mentions. Jira may notify the mentioned account where it supports notifications; jira2py does not guarantee delivery.

Formatted ADF reads from format_issue and formatted comment/worklog helper output are presentation-only: pyadf renders a mention's display text, not its account ID. The identity may be lost if formatted text is edited and written back through a high-level Markdown helper. For identity-safe edits, retrieve and submit raw ADF with the low-level API until dedicated formatted read/edit/write support is available. Native transition fields / update mappings continue to accept Jira ADF directly and do not convert Markdown mentions.

Workflow transitions

Discover the current issue's transitions and transition-screen metadata before choosing the Jira transition ID:

metadata = helpers.metadata.transitions("PROJ-123")
print(metadata.text)
print(metadata.data)  # complete Jira transitions envelope, including fields

accepted = helpers.issues.transition(
    "PROJ-123",
    "31",
    fields={"resolution": {"name": "Done"}},
    update={"labels": [{"add": "released"}]},
)
assert accepted.data["verified"] is False

fields and update are Jira-native mappings and cannot share an exact field key. The helper's successful result means Jira accepted the request; it does not read the issue afterward. Verify the expected destination status and changed fields with api.issues.get_issue(). Transition names remain supported for compatibility, but IDs from fresh discovery avoid ambiguity.

Documentation

License

MIT

Metadata

Release files for jira2py 0.13.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jira2py 0.13.0
File Size Uploaded
jira2py-0.13.0.tar.gz 82.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for jira2py 0.13.0
File Interpreter ABI Platform
jira2py-0.13.0-py3-none-any.whl Python 3 none any Details

Total release size: 148.6 kB

Release files / jira2py-0.13.0.tar.gz

Download URL jira2py-0.13.0.tar.gz
Size 82.8 kB
Tags Source
SHA-256 checksum
How to use checksums
f6fe3b5fa9e2017c094d799808d22f0d0da474b774c0b032f0c56ba7be460e07
BLAKE2b-256 checksum
How to use checksums
3f71ec372bab5d277f181d7e33a041b689a509453446ae29d48b7f1b2f85a5d7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 4, 2026.

Transparency log

Release files / jira2py-0.13.0-py3-none-any.whl

Download URL jira2py-0.13.0-py3-none-any.whl
Size 65.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
eda899113ebd40794be6eb57ab49e6d824b75be5eba5ca3288ee356eebf69c30
BLAKE2b-256 checksum
How to use checksums
a262348ec7625e6aea0a00ca6ff4eb6237c9163cf3c4c07c7ecf8d98c33440e4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 4, 2026.

Transparency log

Release history Release notifications | RSS feed

0.16.1

2 release files

0.16.0

2 release files

This release

0.13.0 This release

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page