brainstorming
Structured design dialogue that validates ideas before implementation begins.
jira-api
Provides Comprehensive reference for Atlassian Jira REST API v3 documentation and best practices. Use when asking about Jira API endpoints, authentication, request/response formats, JQL queries, Atlassian Document Format (ADF), webhooks, error handling, rate limiting, and API usage patterns. Trig...
Full skill instructions
This skill provides authoritative guidance on using the Atlassian Jira REST API v3, including endpoint references, authentication methods, request/response formats, query languages, and best practices for programmatic Jira automation and integration.
To get started with the Jira API:
GET /rest/api/3/issue/{issueIdOrKey}For the project's JiraClient class:
from jira_tool.client import JiraClient
client = JiraClient()
issue = client.get_issue("PROJ-123")
The Jira REST API v3 is the current standard API for Jira Cloud. Key characteristics:
https://{jira-instance}.atlassian.net/rest/api/3/Official Documentation: https://developer.atlassian.com/cloud/jira/platform/rest/v3/
This is what the project uses. Steps:
Authorization: Basic {base64(email:token)}Accept: application/json and Content-Type: application/json headersfrom base64 import b64encode
email = "[email protected]"
api_token = "your-api-token"
credentials = f"{email}:{api_token}"
auth_header = b64encode(credentials.encode()).decode()
headers = {
"Authorization": f"Basic {auth_header}",
"Accept": "application/json",
"Content-Type": "application/json",
}
The JiraClient class handles this automatically:
client = JiraClient(
base_url="https://company.atlassian.net",
username="[email protected]",
api_token="token-from-atlassian"
)
For third-party applications:
Common endpoints you'll use frequently:
Issue Operations
GET /rest/api/3/issue/{issueIdOrKey} - Get issue detailsPOST /rest/api/3/issues - Create issuePUT /rest/api/3/issue/{issueIdOrKey} - Update issueDELETE /rest/api/3/issue/{issueIdOrKey} - Delete issuePOST /rest/api/3/issue/{issueIdOrKey}/comment - Add commentSearching & Filtering
GET /rest/api/3/search - Search issues with JQLPOST /rest/api/3/issues/search - Search (alternative POST method)Projects
GET /rest/api/3/project - List projectsGET /rest/api/3/project/{projectIdOrKey} - Get project detailsUsers
GET /rest/api/3/users/search - Search usersGET /rest/api/3/user?accountId={id} - Get user detailsGET /rest/api/3/myself - Get current userWorkflows & Transitions
GET /rest/api/3/issue/{issueIdOrKey}/transitions - Get available transitionsPOST /rest/api/3/issue/{issueIdOrKey}/transitions - Transition issueCustom Fields
GET /rest/api/3/field - List all fields (including custom)GET /rest/api/3/field/search - Search for fieldsWebhooks
GET /rest/api/3/webhook - List webhooksPOST /rest/api/3/webhook - Create webhookDELETE /rest/api/3/webhook/{id} - Delete webhookMost powerful way to query issues:
GET /rest/api/3/search?jql=project=PROJ AND status="In Progress"&maxResults=50
JQL Examples:
# Recent issues
project = PROJ AND created >= -7d
# Assigned to me
assignee = currentUser()
# Status workflow
status in (Open, "In Progress") AND updated >= -1d
# Custom fields (need field ID)
customfield_10014 = "Epic Name"
# Text search
summary ~ "bug fix" OR description ~ "critical"
# Complex filtering
(project = PROJ OR project = OTHER)
AND status != Done
AND priority >= High
AND created >= 2024-01-01
JQL Functions:
currentUser() - Current authenticated userendOfDay(), startOfDay() - Date functionsnow() - Current timestampissueFunction() - Advanced scriptingCommon parameters for /search:
jql - JQL query stringstartAt - Pagination start (default 0)maxResults - Items per page (default 50, max 100)fields - Comma-separated field names to returnexpand - Additional data to include (changelog, transitions)orderBy - Sort order (e.g., "created DESC")# Using JiraClient
issues = client.search_issues(
jql="project = PROJ AND status = Open",
startAt=0,
maxResults=100,
expand=["changelog"]
)
Request body for POST /rest/api/3/issues:
{
"fields": {
"project": {"key": "PROJ"},
"summary": "Issue summary",
"description": {
"type": "doc",
"version": 1,
"content": [
{
"type": "paragraph",
"content": [{"type": "text", "text": "Description text"}]
}
]
},
"issuetype": {"name": "Task"},
"assignee": {"accountId": "user-account-id"},
"priority": {"name": "High"},
"labels": ["bug", "urgent"]
}
}
PUT /rest/api/3/issue/{issueKey}:
{
"fields": {
"summary": "Updated summary",
"description": {"type": "doc", "version": 1, "content": []},
"priority": {"name": "Medium"},
"assignee": {"accountId": "new-user-id"}
}
}
Use expand parameter to include additional data:
GET /rest/api/3/issue/PROJ-123?expand=changelog,transitions
Common expansions:
changelog - Issue change history (required for state duration analysis)transitions - Available workflow transitionseditmeta - Metadata about what fields can be editednames - Human-readable field namesField Selection - Return only needed fields:
GET /rest/api/3/search?fields=key,summary,status,assignee&maxResults=100
For large result sets, use pagination:
start_at = 0
max_results = 50
all_issues = []
while True:
issues = client.search_issues(
jql="project = PROJ",
startAt=start_at,
maxResults=max_results
)
all_issues.extend(issues)
if len(issues) < max_results:
break
start_at += max_results
Response includes pagination metadata:
{
"startAt": 0,
"maxResults": 50,
"total": 523,
"isLast": false,
"values": [...]
}
Rich text content (descriptions, comments) uses ADF. The project's JiraDocumentBuilder simplifies this:
from jira_tool.formatter import JiraDocumentBuilder
doc = JiraDocumentBuilder()
doc.add_heading("Title", level=1)
doc.add_paragraph(doc.bold("Key"), doc.add_text(": "), doc.add_text("Value"))
doc.add_bullet_list(["Item 1", "Item 2"])
doc.add_code_block("code content", language="python")
adf = doc.build() # Returns ADF dict for API
ADF Structure:
{
"type": "doc",
"version": 1,
"content": [
{
"type": "heading",
"attrs": {"level": 1},
"content": [{"type": "text", "text": "Heading"}]
},
{
"type": "paragraph",
"content": [{"type": "text", "text": "Paragraph"}]
}
]
}
Common ADF nodes:
heading - Headings (levels 1-6)paragraph - Text paragraphsbulletList / orderedList - ListscodeBlock - Code blockspanel - Info panels (info, note, warning, success, error)blockquote - Block quotestable - TablesSee references/reference.md for comprehensive ADF examples.
Common HTTP status codes:
| Code | Meaning | Handling |
|---|---|---|
| 200 | Success | Parse response normally |
| 201 | Created | Resource created successfully |
| 204 | No Content | Successful but empty response |
| 400 | Bad Request | Check request format/parameters |
| 401 | Unauthorized | Check authentication credentials |
| 403 | Forbidden | Check permissions |
| 404 | Not Found | Issue/resource doesn't exist |
| 429 | Too Many Requests | Rate limited - implement backoff |
| 500 | Server Error | Retry with exponential backoff |
Error Response Format:
{
"errorMessages": ["Error message"],
"errors": {
"fieldName": "Field-specific error"
}
}
The JiraClient includes automatic retry logic for 429, 500, 502, 503, 504:
client = JiraClient(max_retries=3) # Automatic exponential backoff
Jira Cloud has rate limits:
X-RateLimit-* headers in responseCheck rate limit headers:
response = client.session.get(url)
print(response.headers.get('X-RateLimit-Limit'))
print(response.headers.get('X-RateLimit-Remaining'))
print(response.headers.get('X-RateLimit-Reset'))
Best practices:
maxResults=100 in searches (fewer requests)Custom fields have IDs (e.g., customfield_10014). They vary per instance.
Discover custom fields:
GET /rest/api/3/field
# Using JiraClient
fields = client.list_fields()
epic_field = client.get_epic_link_field() # Auto-discovers common field IDs
Use in queries and updates:
# In JQL
GET /rest/api/3/search?jql=customfield_10014="Epic Name"
# In updates
PUT /rest/api/3/issue/PROJ-123
{
"fields": {
"customfield_10014": "Epic Name"
}
}
Create Issue Under Epic:
from jira_tool.formatter import JiraDocumentBuilder
doc = JiraDocumentBuilder()
doc.add_paragraph(doc.add_text("Issue description"))
adf = doc.build()
issue_data = {
"fields": {
"project": {"key": "PROJ"},
"summary": "New issue",
"description": adf,
"issuetype": {"name": "Task"},
"customfield_10014": "PROJ-1" # Epic Link field
}
}
response = client.create_issue(issue_data)
Bulk Update Issues:
# Get issues
issues = client.search_issues(
jql="project = PROJ AND status = Open",
maxResults=100
)
# Update each
for issue in issues:
client.update_issue(
issue["key"],
{"fields": {"priority": {"name": "High"}}}
)
Transition Workflow:
# Get available transitions
transitions = client.get_transitions("PROJ-123")
# Find the transition ID you want
for transition in transitions:
if transition["name"] == "Done":
transition_id = transition["id"]
break
# Execute transition
client.transition_issue("PROJ-123", transition_id)
Search and Export:
from jira_tool.analysis.formatters import format_as_csv
issues = client.search_issues(
jql="project = PROJ AND created >= -7d",
expand=["changelog"]
)
csv_output = format_as_csv(issues)
print(csv_output)
Using Jira REST API directly:
curl -X GET \
"https://company.atlassian.net/rest/api/3/issue/PROJ-123" \
-H "Authorization: Basic $(echo -n 'email:token' | base64)" \
-H "Accept: application/json"
Using the project's client:
from jira_tool.client import JiraClient
client = JiraClient()
issue = client.get_issue("PROJ-123")
print(f"Summary: {issue['fields']['summary']}")
print(f"Status: {issue['fields']['status']['name']}")
Find all open bugs assigned to current user:
curl -X GET \
"https://company.atlassian.net/rest/api/3/search" \
-G --data-urlencode 'jql=project=PROJ AND type=Bug AND assignee=currentUser() AND status != Done' \
-G --data-urlencode 'maxResults=100' \
-G --data-urlencode 'expand=changelog' \
-H "Authorization: Basic ..." \
-H "Accept: application/json"
Using the client:
from jira_tool.client import JiraClient
client = JiraClient()
issues = client.search_issues(
jql='project = PROJ AND type = Bug AND assignee = currentUser() AND status != Done',
maxResults=100,
expand=['changelog']
)
for issue in issues:
print(f"{issue['key']}: {issue['fields']['summary']}")
Create a detailed issue with formatted description:
from jira_tool.client import JiraClient
from jira_tool.formatter import JiraDocumentBuilder
client = JiraClient()
# Build rich content
doc = JiraDocumentBuilder()
doc.add_heading("Issue Description", level=1)
doc.add_paragraph(doc.add_text("Background: "), doc.add_text("Detailed background"))
doc.add_heading("Steps to Reproduce", level=2)
doc.add_bullet_list([
"Step 1",
"Step 2",
"Step 3"
])
doc.add_panel("error", doc.add_paragraph(doc.add_text("Expected error")))
adf_description = doc.build()
# Create issue
response = client.create_issue({
"fields": {
"project": {"key": "PROJ"},
"summary": "Bug: Application crashes on login",
"description": adf_description,
"issuetype": {"name": "Bug"},
"priority": {"name": "Highest"},
"labels": ["critical", "regression"]
}
})
print(f"Created issue: {response['key']}")
Use the project's state analyzer to track time in workflow states:
from jira_tool.client import JiraClient
from jira_tool.analysis.state_analyzer import StateDurationAnalyzer
client = JiraClient()
# Search with changelog
issues = client.search_issues(
jql="project = PROJ AND created >= -30d",
expand=["changelog"]
)
# Analyze state transitions
analyzer = StateDurationAnalyzer()
durations = analyzer.analyze_issues(issues)
# Export results
csv_output = analyzer.format_as_csv(durations)
print(csv_output)
Efficiently fetch large result sets:
from jira_tool.client import JiraClient
client = JiraClient()
start_at = 0
max_results = 50
total_fetched = 0
all_issues = []
while True:
issues = client.search_issues(
jql="project = PROJ",
startAt=start_at,
maxResults=max_results
)
all_issues.extend(issues)
total_fetched += len(issues)
# Check if we got fewer results than requested (last page)
if len(issues) < max_results:
break
start_at += max_results
print(f"Fetched {total_fetched} issues...")
print(f"Total issues: {total_fetched}")
requests library (included in project)JIRA_BASE_URL, JIRA_USERNAME, JIRA_API_TOKENsrc/jira_tool/client.pysrc/jira_tool/formatter.pyStructured design dialogue that validates ideas before implementation begins.
Comprehensive design intelligence for web and mobile UI/UX across 10 technology stacks.
Comprehensive implementation plans for multi-step tasks, breaking down specs into bite-sized, testable steps.
Introduction to the obra skills system with mandatory skill invocation rules and best practices.
Execute a written implementation plan with critical review and task checkpoints.
Delegate independent tasks to specialized agents working concurrently with isolated context.
Isolated git worktrees with smart directory selection and safety verification.
Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.
Plan searchable and shareable content that drives traffic, builds authority, and generates leads.
README-first repository scanner that extracts commands and classifies reproduction candidates without executing them.
Brainstorm and prioritize marketing strategies tailored to your SaaS stage, budget, and goals.
Plan and optimize your website's page hierarchy, navigation, URL structure, and internal linking.
The world's fastest calendar for remote work
Capture, organize, and utilize your knowledge effortlessly.
Instant Summaries of Audio & Video Interviews with AnySummary
Transform PDFs into engaging mind maps.
Chat with any PDF instantly
Create an optimal daily plan using your voice
A productivity platform to centralize organizational knowledge and workflows with contextual AI assistance.
AskYourPDF Pricing Plans: Tailored to Your Needs