Hi,
I would like to upload images to Jira Cloud issue and display them in paragraph custom field.
I upload the images using REST API, get the IDs and create ADF with the images details.
But it seems Jira requires the UUID of the images and not the IDs.
Is there a way to get them? the ID !=UUID
import requests
import base64
import json
from PIL import Image
import mimetypes
import os
=== Jira Config ===
=== Upload Attachment ===
def upload_attachment(issue_key, file_path):
url = f"{JIRA_SITE}/rest/api/3/issue/{issue_key}/attachments"
auth = f"{JIRA_CLOUD_EMAIL}:{JIRA_CLOUD_API_TOKEN}"
encoded_auth = base64.b64encode(auth.encode()).decode()
headers = {
"Authorization": f"Basic {encoded_auth}",
"X-Atlassian-Token": "no-check",
"Accept": "application/json"
}
with open(file_path, 'rb') as f:
files = {
'file': (file_path.split("\\")[-1], f)
}
response = requests.post(url, headers=headers, files=files)
if response.status_code in (200, 201):
print("✅ Upload successful")
print(response.json())
return response.json()[0] # First attachment in list
else:
print("❌ Upload failed")
print("Status:", response.status_code)
print(response.text)
return None
=== Build ADF Media Block ===
def build_adf_image_block(attachment):
media_adf = {
“type”: “mediaSingle”,
“attrs”: {
“layout”: “center”
},
“content”: [
{
“type”: “media”,
“attrs”: {
“type”: “file”,
“id”: attachment[“id”],
“collection”: “jira-issue”,
“mimeType”: “image/png”, attachment[“mimeType”],
“width”: 300, # Optional
“height”: 200 # Optional
}
}
]
}
return media_adf
def wrap_adf_blocks_into_doc(blocks, intro_text=None):
“”"
Wrap a list of ADF content blocks into a full ADF document.
:param blocks: List of ADF blocks (e.g. mediaSingle, paragraphs, etc.)
:param intro_text: Optional intro text as a paragraph
:return: ADF document
"""
doc_content = []
if intro_text:
doc_content.append({
"type": "paragraph",
"content": [
{
"type": "text",
"text": intro_text
}
]
})
doc_content.extend(blocks)
return {
"type": "adf_doc",
"version": 1,
"content": doc_content
}
def load_attachment(issue_key, file_path):
# Step 1: Upload the attachment
attachment = upload_attachment(issue_key, file_path)
if not attachment:
raise Exception(f"❌ Failed to upload attachment: {file_path}")
attachment_id = attachment["id"]
mime_type = "image/png" #attachment["mimeType"]
collection = "jira-issue"
# Step 2: Get image dimensions (optional but recommended)
width = height = None
if mime_type.startswith("image/"):
try:
with Image.open(file_path) as img:
width, height = img.size
except Exception as e:
print(f"⚠️ Could not get dimensions for {file_path}: {e}")
# Step 3: Build and return ADF mediaSingle block
return {
"type": "mediaSingle",
"attrs": {
"layout": "center"
},
"content": [
{
"type": "media",
"attrs": {
"type": "file",
"id": attachment_id,
"collection": collection,
"mimeType": mime_type,
"width": width,
"height": height
}
}
]
}
def wrap_adf_blocks_into_doc(blocks, intro_text=None):
content =
if intro_text:
content.append({
"type": "paragraph",
"content": [
{"type": "text", "text": intro_text}
]
})
content.extend(blocks)
return {
"type": "doc",#"adf_doc",
"version": 1,
"content": content
}
files = [r"C:\Pictures\SP7-SP13.png",
r"C:\dog.png"]
blocks = [load_attachment(ISSUE_KEY, f) for f in files]
adf_doc = wrap_adf_blocks_into_doc(blocks, intro_text=“ Attached media:”)
print(json.dumps(adf_doc, indent=2))
provide:
{
“type”: “doc”,
“version”: 1,
“content”: [
{
“type”: “paragraph”,
“content”: [
{
“type”: “text”,
“text”: “\ud83d\udcce Attached media:”
}
]
},
{
“type”: “mediaSingle”,
“attrs”: {
“layout”: “center”
},
“content”: [
{
“type”: “media”,
“attrs”: {
“type”: “file”,
“id”: “10360”,
“collection”: “jira-issue”,
“mimeType”: “image/png”,
“width”: 785,
“height”: 338
}
}
]
},
{
“type”: “mediaSingle”,
“attrs”: {
“layout”: “center”
},
“content”: [
{
“type”: “media”,
“attrs”: {
“type”: “file”,
“id”: “10361”,
“collection”: “jira-issue”,
“mimeType”: “image/png”,
“width”: 518,
“height”: 509
}
}
]
}
]
}
But when setting the custom field, I get
Error fetching projects: 400 - {“errorMessages”:[“INVALID_INPUT”],“errors”:{}}
If I remove the attachment part it works fine.
When insert an image to the custom field manually and use REST to get the issue content I get ADF with UUID, and checking the attachments, I find the relevant attachment with ID which is not the UUID…