atlassian-cli is an independent, community open-source project, not affiliated with, endorsed by, or sponsored by Atlassian, and is not Atlassian's official CLI (acli). Product names are used only to identify compatibility.
The CLI-First Approach
The fastest way to use the Jira API from the command line is not to call it directly. Instead of hand-writing curl requests with base64 auth headers, JSON request bodies, and manual pagination, you run named commands with atlassian-cli and add --format json when you want the raw response. The CLI wraps the same REST endpoints, so atlassian-cli jira issue search is really a GET /search and atlassian-cli jira issue create is really a POST /issue underneath.
The payoff is that you keep the parts of the API that matter (JQL, issue keys, JSON output you can pipe into jq) and drop the parts that slow you down (auth plumbing, pagination loops, and 429 backoff). This post covers the CLI-first way to read, write, and script against Jira. If you specifically need the raw endpoints, paths, and payload shapes, see the sibling Jira REST API guide instead. This one stays at the command layer.
How This Differs (and Where acli Fits)
atlassian-cli is an independent, community, MIT-licensed open-source project. It is not Atlassian's official CLI (acli) and is not affiliated with Atlassian. Use the official acli if you want first-party vendor support. Use atlassian-cli if you want a single free Rust binary that spans Jira, Confluence, Bitbucket, and Jira Service Management with consistent flags and machine-readable output across all of them.
Because every command shares the same --format, --profile, and --limit flags, the muscle memory you build against the Jira API carries straight over to Confluence CQL searches or Bitbucket pull requests. That consistency is the whole point of driving the API through one tool rather than a folder of bespoke curl scripts.
Authenticate Once, Not on Every Request
With raw curl you attach an Authorization header (your email and an Atlassian API token, base64-encoded) to every single call. With the CLI you authenticate once and store the credentials in a named profile:
# One-time login, stored as the "work" profile and set as default
atlassian-cli auth login \
--profile work \
--base-url https://your-site.atlassian.net \
--email you@company.com \
--token $TOKEN \
--default
# Confirm the token works and see who you are
atlassian-cli auth whoami --profile work
The API token comes from your Atlassian account security settings, exactly as it would for a REST call. After this, every command reuses the stored credentials. You can keep several profiles (say work and prod) and target one per command with --profile. For the full auth model, see the authentication and profiles guide.
Reading Data: Search and Get
Reading issues is where you replace GET /rest/api/3/search. Pass a JQL string and cap the result set with --limit rather than looping over startAt and maxResults yourself:
# Search with JQL (the API's GET /search endpoint)
atlassian-cli jira issue search \
--jql "project = DEV order by created desc" \
--limit 5
# Fetch a single issue (GET /issue/{key})
atlassian-cli jira issue get DEV-123
# List projects and inspect one
atlassian-cli jira project list
atlassian-cli jira project get DEV
Every read command takes --format json so you get the same field structure the REST API returns, ready for jq. Need the custom-field IDs that show up in API payloads as customfield_10010? List them directly instead of guessing:
# Discover custom field IDs used in API bodies
atlassian-cli jira fields list --format json | jq '.[] | {id, name}'
Writing Data: Create, Update, Transition, Assign
The write endpoints (POST /issue, PUT /issue/{key}, and the transition endpoint) map to four commands. No JSON body to assemble by hand:
# Create an issue (POST /issue)
atlassian-cli jira issue create \
--project DEV \
--issue-type Task \
--summary "Investigate API latency"
# Update fields (PUT /issue/{key})
atlassian-cli jira issue update DEV-123 --summary "Updated summary"
# Transition through the workflow by name
atlassian-cli jira issue transition DEV-123 --transition "In Progress"
# Assign to a user
atlassian-cli jira issue assign DEV-123 --assignee user@example.com
Custom fields still work when you need them. Pass raw field JSON with --field, using the IDs you discovered from jira fields list:
atlassian-cli jira issue create \
--project DEV \
--issue-type Task \
--summary "cf test" \
--field 'customfield_10010={"value":"Internal"}'
Transitioning issues by name rather than numeric ID is a small thing that removes a whole step from the raw API dance, where you first GET the available transitions to find the right ID before you POST.
Sprint membership is another place the CLI hides API friction. On the raw Agile API you have to know the sprint custom-field ID and send it in the body. Here you pass the numeric sprint ID directly, at create time or on an existing issue:
# Put an existing issue into a sprint by numeric ID
atlassian-cli jira issue update DEV-123 --sprint 25446
# Or create it straight into the sprint
atlassian-cli jira issue create \
--project DEV --issue-type Task \
--summary "In sprint" --sprint 25446
JSON Output and jq: The API Response Layer
This is where the CLI-first approach shines. Any command emits clean JSON with --format json (or -f json), and you compose real queries with jq:
# Just the issue keys
atlassian-cli jira issue search --jql "project = DEV" \
--format json | jq '.[].key'
# Count bugs grouped by priority
atlassian-cli jira issue search \
--jql "project = DEV AND type = Bug" \
--format json | jq 'group_by(.fields.priority.name)
| map({priority: .[0].fields.priority.name, count: length})'
When you want the total count alongside the rows, add --envelope to wrap list output as {"data": [...], "count": N}. And for CI gating, --format quiet returns an exit code only:
# Envelope form for downstream parsing
atlassian-cli jira issue search --jql "project = DEV" \
--format json --envelope | jq '.count'
# Exit-code-only check, useful in a pipeline gate
atlassian-cli auth test --profile prod --format quiet && echo OK
Beyond JSON, the same data flows out as csv, yaml, markdown, or a human-readable table. Reach for --output issues.csv to write a spreadsheet-ready file directly. Debugging a call? Add --debug to log the underlying HTTP request and response, which is the closest thing to watching the raw API traffic.
atlassian-cli vs. the Raw Jira API
Here is the same set of tasks, done against the raw REST API versus through the CLI. The endpoints are identical underneath. Only the amount of plumbing you write changes.
| Task | Raw Jira REST API | atlassian-cli |
|---|---|---|
| Auth | Base64 email:token header on every request |
auth login once, stored in a profile |
| Search | GET /search, loop startAt/maxResults |
jira issue search --jql "..." --limit N |
| Create | POST /issue with a hand-built JSON body |
jira issue create --project ... --summary ... |
| Transition | GET transitions, then POST by ID |
jira issue transition KEY --transition "Done" |
| Output | Raw JSON, parse it yourself | --format json|csv|yaml|table|markdown |
| Rate limits | Detect 429 and back off yourself | Built-in backoff on bulk commands |
Scripting Real Workflows
Because the CLI already handles auth and output, a shell script becomes a short, readable sequence of API calls. This example pulls a triage report and reassigns unowned bugs without a single curl header in sight:
#!/bin/bash
# Daily triage: report open bugs, claim unassigned ones
set -euo pipefail
PROFILE="work"
# How many open bugs are there right now?
open_bugs=$(atlassian-cli jira issue search \
--profile "$PROFILE" \
--jql "project = DEV AND type = Bug AND status != Done" \
--format json | jq 'length')
echo "Open bugs: $open_bugs"
# Assign unowned bugs to the triage lead (bulk endpoint)
atlassian-cli jira bulk assign \
--profile "$PROFILE" \
--jql "project = DEV AND type = Bug AND assignee is EMPTY" \
--assignee triage-lead@company.com \
--dry-run
The jira bulk subcommands are how you fan a single logical action across hundreds of issues. They accept --dry-run to preview, --concurrency to tune parallel requests, and they page through the whole result set for you. To trigger changes on a schedule or in response to events rather than by hand, the Jira automation guide shows how to wire these commands into cron and CI.
For copy-pasteable syntax on every flag and subcommand, keep the command reference open in a second tab.
Try atlassian-cli
One free binary for the Jira API and the rest of the Atlassian suite. No SDK, no curl scripts.
Install atlassian-cliFAQ
Do I need to write curl scripts to use the Jira API?
No. atlassian-cli wraps the same Jira REST API endpoints behind named commands, so you run atlassian-cli jira issue search or atlassian-cli jira issue create instead of hand-writing curl calls with Authorization headers and JSON bodies. Add --format json to any command to get the raw API-style response back for piping into jq. You only drop down to raw curl when you need an endpoint the CLI does not yet cover.
How do I authenticate to the Jira API from the command line?
Run atlassian-cli auth login once with your site URL, email, and an Atlassian API token: atlassian-cli auth login --profile work --base-url https://your-site.atlassian.net --email you@company.com --token $TOKEN --default. The credentials are stored in a named profile, so every later command reuses them. You do not paste an Authorization header on each request the way you would with raw curl.
How do I get Jira API results as JSON I can pipe to jq?
Add --format json (or -f json) to any read command and pipe it into jq. For example: atlassian-cli jira issue search --jql "project = DEV" --format json | jq '.[].key'. Use --envelope to wrap list output as {"data": [...], "count": N} when you want the total count alongside the rows.
Is atlassian-cli the same as Atlassian's official CLI (acli)?
No. atlassian-cli is an independent, community, MIT-licensed open-source project and is not affiliated with Atlassian. Atlassian ships its own official CLI called acli. Use acli if you want first-party vendor support; use atlassian-cli if you want a single free Rust binary that spans Jira, Confluence, Bitbucket, and Jira Service Management with consistent flags and JSON output.
Does the CLI handle Jira API pagination and rate limits for me?
Yes. Instead of looping over startAt and maxResults yourself, you cap results with --limit and let the CLI walk the underlying pages, and bulk commands page through the whole result set for you. Bulk operations also back off automatically when the Atlassian Cloud API returns a 429 Too Many Requests response, so long-running jobs finish without manual retry logic.