Skip to content
Learn Agentic AI10 min read0 views

Building a Jira AI Agent: Ticket Creation, Updates, and Sprint Management

Build an AI agent that integrates with Jira for automated ticket creation, intelligent updates, JQL-powered queries, and sprint management using the Jira REST API with practical Python examples.

Why Build AI Agents for Jira

Jira is the backbone of project tracking for software teams. An AI agent connected to Jira can automate ticket creation from Slack messages or emails, enrich tickets with context from codebases, estimate story points based on historical data, manage sprint planning, and generate sprint retrospective summaries — turning Jira from a manual data entry system into an intelligent project assistant.

Setting Up the Jira Client

Use API tokens for Jira Cloud authentication. The REST API provides comprehensive access to issues, boards, sprints, and workflows.

import httpx
from base64 import b64encode

class JiraClient:
    def __init__(self, domain: str, email: str, api_token: str):
        credentials = b64encode(
            f"{email}:{api_token}".encode()
        ).decode()
        self.http = httpx.AsyncClient(
            base_url=f"https://{domain}.atlassian.net/rest/api/3",
            headers={
                "Authorization": f"Basic {credentials}",
                "Content-Type": "application/json",
            },
            timeout=30.0,
        )

    async def create_issue(self, project_key: str, summary: str,
                           description: str, issue_type: str = "Task",
                           priority: str = "Medium",
                           labels: list[str] = None) -> dict:
        payload = {
            "fields": {
                "project": {"key": project_key},
                "summary": summary,
                "description": {
                    "type": "doc",
                    "version": 1,
                    "content": [
                        {
                            "type": "paragraph",
                            "content": [
                                {"type": "text", "text": description}
                            ],
                        }
                    ],
                },
                "issuetype": {"name": issue_type},
                "priority": {"name": priority},
            }
        }
        if labels:
            payload["fields"]["labels"] = labels

        response = await self.http.post("/issue", json=payload)
        response.raise_for_status()
        return response.json()

    async def search_issues(self, jql: str, max_results: int = 50) -> list:
        response = await self.http.post(
            "/search",
            json={
                "jql": jql,
                "maxResults": max_results,
                "fields": [
                    "summary", "status", "assignee",
                    "priority", "created", "updated",
                ],
            },
        )
        response.raise_for_status()
        return response.json()["issues"]

AI-Powered Ticket Creation

Let the agent parse unstructured requests — from Slack messages, emails, or voice transcripts — and create well-formatted Jira tickets.

async def create_ticket_from_request(
    jira: JiraClient,
    agent,
    raw_request: str,
    project_key: str,
):
    # Agent structures the raw input into Jira fields
    structured = await agent.run(
        prompt=(
            f"Parse this request into a Jira ticket.\n"
            f"Determine: summary (one line), description (detailed), "
            f"issue_type (Bug/Task/Story), priority (Highest/High/Medium/Low/Lowest), "
            f"and relevant labels.\n\n"
            f"Request: {raw_request}"
        )
    )

    ticket = await jira.create_issue(
        project_key=project_key,
        summary=structured.summary,
        description=structured.description,
        issue_type=structured.issue_type,
        priority=structured.priority,
        labels=structured.labels,
    )

    return ticket["key"]

JQL Queries for Intelligent Context

JQL (Jira Query Language) gives your agent powerful search capabilities. Use it to gather context before making decisions.

See AI Voice Agents Handle Real Calls

Book a free demo or calculate how much you can save with AI voice automation.

async def get_sprint_health(jira: JiraClient, project_key: str) -> dict:
    # Find current sprint issues
    in_progress = await jira.search_issues(
        f'project = {project_key} AND sprint in openSprints() '
        f'AND status = "In Progress"'
    )
    done = await jira.search_issues(
        f'project = {project_key} AND sprint in openSprints() '
        f'AND status = "Done"'
    )
    todo = await jira.search_issues(
        f'project = {project_key} AND sprint in openSprints() '
        f'AND status = "To Do"'
    )
    blocked = await jira.search_issues(
        f'project = {project_key} AND sprint in openSprints() '
        f'AND status = "Blocked"'
    )

    return {
        "total": len(in_progress) + len(done) + len(todo) + len(blocked),
        "done": len(done),
        "in_progress": len(in_progress),
        "todo": len(todo),
        "blocked": len(blocked),
        "completion_pct": round(
            len(done) / max(len(in_progress) + len(done) + len(todo) + len(blocked), 1) * 100
        ),
    }

Workflow Transitions

Moving tickets through workflow states requires knowing the available transitions for the current status.

async def transition_issue(
    jira: JiraClient, issue_key: str, target_status: str
):
    # Get available transitions
    response = await jira.http.get(
        f"/issue/{issue_key}/transitions"
    )
    transitions = response.json()["transitions"]

    # Find the transition that leads to our target status
    transition = next(
        (t for t in transitions if t["to"]["name"] == target_status),
        None,
    )

    if not transition:
        available = [t["to"]["name"] for t in transitions]
        raise ValueError(
            f"Cannot transition to '{target_status}'. "
            f"Available: {available}"
        )

    await jira.http.post(
        f"/issue/{issue_key}/transitions",
        json={"transition": {"id": transition["id"]}},
    )

# Agent-driven bulk status update
async def close_stale_tickets(jira: JiraClient, project_key: str, agent):
    stale = await jira.search_issues(
        f'project = {project_key} AND status = "In Progress" '
        f'AND updated <= -14d'
    )

    for issue in stale:
        key = issue["key"]
        summary = issue["fields"]["summary"]

        decision = await agent.run(
            prompt=f"Ticket {key} ('{summary}') has not been updated in "
                   f"14 days. Should we move it to Blocked, close it, "
                   f"or leave it? Explain briefly."
        )

        if decision.action != "leave":
            await transition_issue(jira, key, decision.target_status)
            await jira.http.post(
                f"/issue/{key}/comment",
                json={"body": {
                    "type": "doc", "version": 1,
                    "content": [{"type": "paragraph", "content": [
                        {"type": "text", "text": f"AI Agent: {decision.reason}"}
                    ]}]
                }},
            )

FAQ

How do I handle Jira's Atlassian Document Format for descriptions?

Jira Cloud V3 API uses Atlassian Document Format (ADF), a JSON-based rich text format. Simple text wraps in paragraph nodes as shown above. For complex formatting (tables, code blocks, bullet lists), build nested ADF node structures. Consider writing a helper function that converts markdown to ADF to simplify agent output formatting.

What are the Jira API rate limits?

Jira Cloud allows roughly 100 requests per minute for basic plans and higher limits for premium. Implement rate limiting on your client side with a token bucket or semaphore. The API returns Retry-After headers on 429 responses — respect those values before retrying.

Can the AI agent assign tickets to specific team members?

Yes. Use the assignee field in the create or update payload with the user's Atlassian account ID. To find account IDs, query /rest/api/3/user/search?query=username. Your agent can learn team members' areas of expertise and intelligently assign based on ticket content and past assignments.


#Jira #ProjectManagement #RESTAPI #AIAgents #SprintManagement #AgenticAI #LearnAI #AIEngineering

Share this article
C

CallSphere Team

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.