Install
openclaw skills install jira-rest-v3Perform Jira Cloud daily tasks via REST API v3: search, create, update, assign issues; manage comments, worklogs; and handle boards, sprints, transitions.
openclaw skills install jira-rest-v3Use this skill to perform everyday Jira work from openClaw:
This skill assumes Jira Cloud.
When a user explicitly asks for Jira work, or when a task clearly requires Jira data, do not merely describe the REST API.
You MUST do all of the following:
If the environment is Linux, prefer curl.
If the environment is Windows, prefer either curl.exe or PowerShell Invoke-RestMethod.
Never stop at “the API endpoint would be …”. The skill is only considered applied when the actual CLI request is made.
All variables MUST use the ATREST_ prefix.
ATREST_JIRA_BASE_URL
https://your-domain.atlassian.netATREST_JIRA_AUTH_MODE
basic (recommended for scripts) or bearerATREST_JIRA_EMAIL
ATREST_JIRA_AUTH_MODE=basicATREST_JIRA_API_TOKEN
ATREST_JIRA_AUTH_MODE=basicATREST_JIRA_BEARER_TOKEN
ATREST_JIRA_AUTH_MODE=bearerATREST_JIRA_USER_AGENT
openClaw-jira-atrest/1.0ATREST_JIRA_DEFAULT_PROJECT_KEYATREST_JIRA_DEFAULT_ISSUE_TYPE
Task, Bug, StoryATREST_JIRA_DEFAULT_BOARD_IDATREST_JIRA_DEFAULT_MAX_RESULTS
50ATREST_JIRA_DEFAULT_FIELDS
summary,status,assignee,priority,updatedATREST_HTTP_TIMEOUT_MS (e.g. 30000)ATREST_HTTP_RETRY_MAX (e.g. 3)ATREST_HTTP_RETRY_BACKOFF_MS (e.g. 1000)See also: refs/openclaw_env_example.json.
${ATREST_JIRA_BASE_URL}/rest/api/3${ATREST_JIRA_BASE_URL}/rest/agile/1.0When selecting an endpoint, always choose the correct base family first.
Authorization: Basic <base64(email:apiToken)>, orAuthorization: Bearer ${ATREST_JIRA_BEARER_TOKEN}Never print secrets, never echo tokens into logs, never store tokens in repo.
Jira Cloud v3 uses Atlassian Document Format (ADF) for:
description, environment, and textarea custom fieldsbodycommentWhen the user provides plain text, wrap it into minimal ADF.
See refs/jira-json-quickref.md#adf-minimal.
For every Jira command, execute the request through the OS shell.
Accept: application/jsonContent-Type: application/json for requests with JSON bodyUser-Agent: ${ATREST_JIRA_USER_AGENT} if setAuthorization: ... according to auth modePOST and PUT, write the JSON body into a temporary file whenever the payload is non-trivial.Use Bash + curl.
: "${ATREST_JIRA_BASE_URL:?Missing ATREST_JIRA_BASE_URL}"
: "${ATREST_JIRA_AUTH_MODE:?Missing ATREST_JIRA_AUTH_MODE}"
JIRA_BASE="${ATREST_JIRA_BASE_URL}"
JIRA_UA="${ATREST_JIRA_USER_AGENT:-openClaw-jira-atrest/1.0}"
if [ "${ATREST_JIRA_AUTH_MODE}" = "basic" ]; then
: "${ATREST_JIRA_EMAIL:?Missing ATREST_JIRA_EMAIL}"
: "${ATREST_JIRA_API_TOKEN:?Missing ATREST_JIRA_API_TOKEN}"
AUTH_HEADER="Authorization: Basic $(printf '%s' "${ATREST_JIRA_EMAIL}:${ATREST_JIRA_API_TOKEN}" | base64 | tr -d '\n')"
elif [ "${ATREST_JIRA_AUTH_MODE}" = "bearer" ]; then
: "${ATREST_JIRA_BEARER_TOKEN:?Missing ATREST_JIRA_BEARER_TOKEN}"
AUTH_HEADER="Authorization: Bearer ${ATREST_JIRA_BEARER_TOKEN}"
else
echo "Unsupported ATREST_JIRA_AUTH_MODE=${ATREST_JIRA_AUTH_MODE}" >&2
exit 1
fi
curl --silent --show-error --fail \
--request GET \
--url "${JIRA_BASE}/rest/api/3/issue/PROJ-123?fields=summary,status,assignee,updated" \
--header "Accept: application/json" \
--header "$AUTH_HEADER" \
--header "User-Agent: ${JIRA_UA}"
cat > /tmp/jira-body.json <<'JSON'
{
"fields": {
"project": { "key": "PROJ" },
"issuetype": { "name": "Task" },
"summary": "Created from openClaw"
}
}
JSON
curl --silent --show-error --fail \
--request POST \
--url "${JIRA_BASE}/rest/api/3/issue" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "$AUTH_HEADER" \
--header "User-Agent: ${JIRA_UA}" \
--data-binary @/tmp/jira-body.json
jq is available, use it for formatting and extraction.Example:
curl --silent --show-error --fail ... | jq -r '.key, .fields.summary'
Use either PowerShell Invoke-RestMethod or curl.exe.
Important:
curl can be an alias.curl.exe explicitly.if (-not $env:ATREST_JIRA_BASE_URL) { throw "Missing ATREST_JIRA_BASE_URL" }
if (-not $env:ATREST_JIRA_AUTH_MODE) { throw "Missing ATREST_JIRA_AUTH_MODE" }
$JiraBase = $env:ATREST_JIRA_BASE_URL.TrimEnd('/')
$JiraUa = if ($env:ATREST_JIRA_USER_AGENT) { $env:ATREST_JIRA_USER_AGENT } else { 'openClaw-jira-atrest/1.0' }
if ($env:ATREST_JIRA_AUTH_MODE -eq 'basic') {
if (-not $env:ATREST_JIRA_EMAIL) { throw 'Missing ATREST_JIRA_EMAIL' }
if (-not $env:ATREST_JIRA_API_TOKEN) { throw 'Missing ATREST_JIRA_API_TOKEN' }
$pair = "{0}:{1}" -f $env:ATREST_JIRA_EMAIL, $env:ATREST_JIRA_API_TOKEN
$basic = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($pair))
$AuthHeader = "Basic $basic"
}
elseif ($env:ATREST_JIRA_AUTH_MODE -eq 'bearer') {
if (-not $env:ATREST_JIRA_BEARER_TOKEN) { throw 'Missing ATREST_JIRA_BEARER_TOKEN' }
$AuthHeader = "Bearer $($env:ATREST_JIRA_BEARER_TOKEN)"
}
else {
throw "Unsupported ATREST_JIRA_AUTH_MODE=$($env:ATREST_JIRA_AUTH_MODE)"
}
$Headers = @{
Accept = 'application/json'
Authorization = $AuthHeader
'User-Agent' = $JiraUa
}
$response = Invoke-RestMethod `
-Method Get `
-Uri "$JiraBase/rest/api/3/issue/PROJ-123?fields=summary,status,assignee,updated" `
-Headers $Headers
$response.key
$response.fields.summary
$payload = @{
fields = @{
project = @{ key = 'PROJ' }
issuetype = @{ name = 'Task' }
summary = 'Created from openClaw'
}
} | ConvertTo-Json -Depth 20
$tmp = Join-Path $env:TEMP 'jira-body.json'
Set-Content -Path $tmp -Value $payload -Encoding UTF8
$Headers['Content-Type'] = 'application/json'
$response = Invoke-RestMethod `
-Method Post `
-Uri "$JiraBase/rest/api/3/issue" `
-Headers $Headers `
-Body (Get-Content -Path $tmp -Raw)
curl.exe --silent --show-error --fail `
--request GET `
--url "$JiraBase/rest/api/3/issue/PROJ-123?fields=summary,status,assignee,updated" `
--header "Accept: application/json" `
--header "Authorization: $AuthHeader" `
--header "User-Agent: $JiraUa"
Whenever possible, define one reusable request helper in the active shell session and use it for all Jira calls.
A ready-to-copy reference is provided in:
refs/cli-rest-quickref.mdThis dramatically increases the chance that openClaw actually performs the HTTP call instead of drifting into abstract API discussion.
200 / 201: parse and summarize JSON response204: report success, then optionally follow up with a GET if the user expects the updated resource400: invalid payload, invalid JQL, missing required fields, or bad field ids401: missing or invalid authentication403: authenticated but missing permission or blocked by project/board rules404: resource not found, wrong key/id, or inaccessible resource409: conflict (workflow/state/business rule)429: rate limit; respect Retry-After if present, then retry with backoffAlways explain the Jira-specific cause as clearly as possible.
For jira.issues.searchJql:
nextPageToken until isLast=trueFor endpoints that use startAt and maxResults:
The following mappings are normative. They are not examples only; they define how openClaw should actually perform the CLI call.
/rest/api/3/project/searchstartAt, maxResults, optional filters supported by Jira/rest/api/3/user/searchquery (string), optional pagination params supported by JiraaccountId/rest/api/3/search/jql (or POST for very long JQL)jql, nextPageToken, maxResults, fields[], expand, properties[], fieldsByKeys, failFast, reconcileIssues[]nextPageToken until isLast=trueATREST_JIRA_DEFAULT_MAX_RESULTS and ATREST_JIRA_DEFAULT_FIELDS if provided--get --data-urlencode or a fully encoded URL; for PowerShell prefer a URI string with encoded query parameters/rest/api/3/issue/{issueIdOrKey}fields (comma-separated or array, depending on client), expand/rest/api/3/issue/{issueIdOrKey}/changelogstartAt, maxResults/rest/api/3/issuerefs/jira-json-quickref.md#issue-createproject, issuetype, summarydescription (ADF), priority, labels, assignee (accountId)/rest/api/3/issue/{issueIdOrKey}notifyUsers, returnIssue, overrideScreenSecurity, overrideEditableFlag, expandfields and/or update (operations)refs/jira-json-quickref.md#issue-edit204 unless returnIssue=true/rest/api/3/issue/{issueIdOrKey}/assignee{ "accountId": "..." } (or null for unassigned where allowed)204/rest/api/3/issue/{issueIdOrKey}/transitionsexpand, optional filters supported by Jira/rest/api/3/issue/{issueIdOrKey}/transitions{ "transition": { "id": "X" }, ... } optionally plus update.comment.add etc.refs/jira-json-quickref.md#issue-transition204/rest/api/3/issue/{issueIdOrKey}deleteSubtasks (optional)204/rest/api/3/issue/{issueIdOrKey}/commentstartAt, maxResults, orderBy, expand/rest/api/3/issue/{issueIdOrKey}/comment{ "body": <ADF>, "visibility": <optional>, "properties": <optional> }refs/jira-json-quickref.md#comment-add/rest/api/3/issue/{issueIdOrKey}/comment/{id}body / visibility / properties)/rest/api/3/issue/{issueIdOrKey}/comment/{id}204/rest/api/3/issue/{issueIdOrKey}/worklogtimeSpentSeconds/rest/api/3/issue/{issueIdOrKey}/worklogrefs/jira-json-quickref.md#worklog-add/rest/agile/1.0/boardstartAt, maxResults, filters like type, name, projectKeyOrId, etc./rest/agile/1.0/board/{boardId}/rest/agile/1.0/board/{boardId}/backlogstartAt, maxResults, jql, fields, expand/rest/agile/1.0/board/{boardId}/issuestartAt, maxResults, jql, fields, expand/rest/agile/1.0/board/{boardId}/sprintstartAt, maxResults, state/rest/agile/1.0/board/{boardId}/sprint/{sprintId}/issuestartAt, maxResults, optional filters/rest/agile/1.0/sprintrefs/jira-json-quickref.md#sprint-create/rest/agile/1.0/sprint/{sprintId}/rest/agile/1.0/sprint/{sprintId}/rest/agile/1.0/sprint/{sprintId}/issue/rest/agile/1.0/sprint/{sprintId}/issue{ "issues": ["PROJ-1", "PROJ-2", ...] }204 on successThese are concrete examples to reduce ambiguity.
JQL='project = PROJ AND statusCategory != Done ORDER BY updated DESC'
curl --silent --show-error --fail --get \
--url "${JIRA_BASE}/rest/api/3/search/jql" \
--data-urlencode "jql=${JQL}" \
--data-urlencode "maxResults=${ATREST_JIRA_DEFAULT_MAX_RESULTS:-50}" \
--data-urlencode "fields=${ATREST_JIRA_DEFAULT_FIELDS:-summary,status,assignee,priority,updated}" \
--header "Accept: application/json" \
--header "$AUTH_HEADER" \
--header "User-Agent: ${JIRA_UA}"
$jql = 'project = PROJ AND statusCategory != Done ORDER BY updated DESC'
$maxResults = if ($env:ATREST_JIRA_DEFAULT_MAX_RESULTS) { $env:ATREST_JIRA_DEFAULT_MAX_RESULTS } else { '50' }
$uri = "$JiraBase/rest/api/3/search/jql?maxResults=$maxResults&fields=summary,status,assignee,priority,updated&jql=$([uri]::EscapeDataString($jql))"
Invoke-RestMethod -Method Get -Uri $uri -Headers $Headers
cat > /tmp/comment.json <<'JSON'
{
"body": {
"type": "doc",
"version": 1,
"content": [
{
"type": "paragraph",
"content": [
{ "type": "text", "text": "Work completed and verified." }
]
}
]
}
}
JSON
curl --silent --show-error --fail \
--request POST \
--url "${JIRA_BASE}/rest/api/3/issue/PROJ-123/comment" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "$AUTH_HEADER" \
--header "User-Agent: ${JIRA_UA}" \
--data-binary @/tmp/comment.json
$transitionPayload = @{
transition = @{ id = '31' }
} | ConvertTo-Json -Depth 10
$Headers['Content-Type'] = 'application/json'
Invoke-RestMethod `
-Method Post `
-Uri "$JiraBase/rest/api/3/issue/PROJ-123/transitions" `
-Headers $Headers `
-Body $transitionPayload
When replying to the user after an API call:
KEY — Summary (Status) [Assignee] updated <date>These are strongly recommended additions to prompts and agent behavior.
Add wording like:
jira.* action, execute a real CLI HTTP request. Do not stop at endpoint explanation.”curl; on Windows use curl.exe or Invoke-RestMethod.”Add wording like:
This prevents the most common quoting failures.
Require the agent to think in this order:
Before complex Jira work, allow the agent to verify connectivity with a harmless call such as:
GET /rest/api/3/myselfGET /rest/api/3/project/search?maxResults=1Do not let the agent improvise between many different HTTP clients.
curlInvoke-RestMethod or curl.exeFor assignees, transitions, board ids, and sprint ids, first resolve the exact Jira identifier, then perform the write operation.
For patterns and ready-to-copy ADF payload snippets, including an example for “ContentCraft: Mermaid Diagrams for Jira”, see:
refs/app-embedding-quickref.mdrefs/jira-json-quickref.md (payload shapes, short parameter notes, ADF helper)refs/jql-cheatsheet.md (ready-to-use JQL patterns)refs/openclaw_env_example.json (env snippet)refs/app-embedding-quickref.md (how to embed app data into Jira text bodies; includes ContentCraft Mermaid example)refs/cli-rest-quickref.md (Linux Bash + Windows PowerShell reusable request helpers and concrete REST execution examples)