Claude
Skills
Sign in
Back

atlassian-attachments

Included with Lifetime
$97 forever

Attach documents, screenshots, PDFs, and files to Jira issues and Confluence pages via REST API. Use when uploading evidence, documentation, or media to Atlassian products.

Backend & APIs

What this skill does


# Atlassian Attachments Skill

Attach files, screenshots, and documents to Jira issues and Confluence pages using the Atlassian REST API.

## Authentication Setup

### API Token (Required)

Generate an API token at: https://id.atlassian.com/manage-profile/security/api-tokens

### Environment Variables

```bash
export ATLASSIAN_DOMAIN="your-domain"
export ATLASSIAN_EMAIL="[email protected]"
export ATLASSIAN_API_TOKEN="your-api-token"
```

### Setup via .envrc (Recommended)

If environment variables are not set, add them to `.envrc` in your project root for automatic loading with [direnv](https://direnv.net/):

```bash
# .envrc
export ATLASSIAN_DOMAIN="your-domain"
export ATLASSIAN_EMAIL="[email protected]"
export ATLASSIAN_API_TOKEN="your-api-token"
```

Then allow the file:
```bash
direnv allow
```

**Security Note:** Add `.envrc` to `.gitignore` to prevent committing credentials:
```bash
echo ".envrc" >> .gitignore
```

### Check Environment Setup

```bash
# Verify variables are set
echo "Domain: ${ATLASSIAN_DOMAIN:-NOT SET}"
echo "Email: ${ATLASSIAN_EMAIL:-NOT SET}"
echo "Token: ${ATLASSIAN_API_TOKEN:+SET}"
```

If any show "NOT SET", prompt the user to configure `.envrc`.

### Base URLs

```
Jira:       https://{domain}.atlassian.net/rest/api/3
Confluence: https://{domain}.atlassian.net/wiki/rest/api
```

## Jira REST API - Upload Attachments

### Endpoint

```
POST https://{domain}.atlassian.net/rest/api/3/issue/{issueIdOrKey}/attachments
```

### Required Headers

| Header | Value | Purpose |
|--------|-------|---------|
| `X-Atlassian-Token` | `no-check` | CSRF protection bypass (required) |
| `Content-Type` | `multipart/form-data` | File upload format |

### cURL Command

```bash
curl --location --request POST \
  'https://your-domain.atlassian.net/rest/api/3/issue/PROJ-123/attachments' \
  -u '[email protected]:<api_token>' \
  -H 'X-Atlassian-Token: no-check' \
  --form 'file=@"./screenshots/bug-evidence.png"'
```

### Python Example

```python
import requests
from requests.auth import HTTPBasicAuth

def upload_jira_attachment(domain, email, api_token, issue_key, file_path):
    url = f"https://{domain}.atlassian.net/rest/api/3/issue/{issue_key}/attachments"

    auth = HTTPBasicAuth(email, api_token)
    headers = {
        "X-Atlassian-Token": "no-check"
    }

    with open(file_path, 'rb') as file:
        files = {'file': file}
        response = requests.post(url, auth=auth, headers=headers, files=files)

    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"Upload failed: {response.status_code} - {response.text}")

# Usage
result = upload_jira_attachment(
    domain="your-domain",
    email="[email protected]",
    api_token="your-api-token",
    issue_key="PROJ-123",
    file_path="./screenshots/bug-evidence.png"
)
```

### Bash Script - Multiple Files

```bash
#!/bin/bash
DOMAIN="your-domain"
EMAIL="[email protected]"
API_TOKEN="your-api-token"
ISSUE_KEY="PROJ-123"
FILES_DIR="./qa-tests/screenshots/"

for file in "$FILES_DIR"*.png; do
    echo "Uploading: $file"
    curl --silent --location --request POST \
      "https://${DOMAIN}.atlassian.net/rest/api/3/issue/${ISSUE_KEY}/attachments" \
      -u "${EMAIL}:${API_TOKEN}" \
      -H "X-Atlassian-Token: no-check" \
      --form "file=@\"$file\""
    echo " Done"
done
```

## Confluence REST API - Upload Attachments

### Endpoint

```
POST https://{domain}.atlassian.net/wiki/rest/api/content/{pageId}/child/attachment
```

### Required Headers

| Header | Value | Purpose |
|--------|-------|---------|
| `X-Atlassian-Token` | `nocheck` | CSRF protection bypass (required) |
| `Content-Type` | `multipart/form-data` | File upload format |

### cURL Command - Basic Auth

```bash
curl -u "${USER_EMAIL}:${API_TOKEN}" \
  -X POST \
  -H "X-Atlassian-Token: nocheck" \
  -F "file=@./diagram.png" \
  -F "comment=Uploaded via REST API" \
  "https://${DOMAIN}.atlassian.net/wiki/rest/api/content/${PAGE_ID}/child/attachment"
```

### cURL Command - Personal Access Token

```bash
curl -X POST \
  -H "Authorization: Bearer ${PAT_TOKEN}" \
  -H "X-Atlassian-Token: no-check" \
  -H "Content-Type: multipart/form-data" \
  -F "file=@./document.pdf" \
  "https://${DOMAIN}.atlassian.net/wiki/rest/api/content/${PAGE_ID}/child/attachment"
```

### Python Example

```python
import requests
from requests.auth import HTTPBasicAuth

def upload_confluence_attachment(domain, email, api_token, page_id, file_path, comment=""):
    url = f"https://{domain}.atlassian.net/wiki/rest/api/content/{page_id}/child/attachment"

    auth = HTTPBasicAuth(email, api_token)
    headers = {
        "X-Atlassian-Token": "nocheck"
    }

    with open(file_path, 'rb') as file:
        files = {'file': file}
        data = {'comment': comment} if comment else {}
        response = requests.post(url, auth=auth, headers=headers, files=files, data=data)

    if response.status_code in [200, 201]:
        return response.json()
    else:
        raise Exception(f"Upload failed: {response.status_code} - {response.text}")

# Usage
result = upload_confluence_attachment(
    domain="your-domain",
    email="[email protected]",
    api_token="your-api-token",
    page_id="123456789",
    file_path="./docs/architecture.png",
    comment="Architecture diagram v2"
)
```

### Get Page ID by Title

```bash
# Find page ID from title
curl -u "${EMAIL}:${API_TOKEN}" \
  "https://${DOMAIN}.atlassian.net/wiki/rest/api/content?title=Page%20Title&spaceKey=SPACE" \
  | jq '.results[0].id'
```

### Embed Attachment in Page Content

After uploading, the attachment is in the page's attachment list but **NOT embedded** in content. You must update the page body to display it.

#### Important: Use Markdown, Not Wiki Markup

| Format | Syntax | Works with API? |
|--------|--------|-----------------|
| Wiki markup | `!image.png!` | **NO** - Not converted |
| Markdown | `![alt text](image.png)` | **YES** - Converted to storage format |
| Storage format | `<ac:image>...</ac:image>` | **YES** - Native format |

**Key insight:** Markdown image syntax gets automatically converted to Confluence storage format when using the API.

#### CRITICAL: Storage Format for Attachments vs External URLs

When using storage format directly, you MUST use the correct element for referencing attachments:

| Reference Type | Element | Use Case |
|----------------|---------|----------|
| Page attachment | `<ri:attachment ri:filename="..."/>` | Files uploaded to the page |
| External URL | `<ri:url ri:value="..."/>` | External image URLs |

**WRONG - Using ri:url for attachments (images won't display):**
```xml
<ac:image ac:src="screenshot.png">
  <ri:url ri:value="screenshot.png" />
</ac:image>
```

**CORRECT - Using ri:attachment for uploaded files:**
```xml
<ac:image>
  <ri:attachment ri:filename="screenshot.png" />
</ac:image>
```

The `ri:url` element is for external URLs only. For files uploaded as attachments to the page, you MUST use `ri:attachment` with `ri:filename`.

#### Method 1: Markdown (Recommended)

Use `representation: "wiki"` with Markdown syntax:

```bash
curl -u "${EMAIL}:${API_TOKEN}" \
  -X PUT \
  -H "Content-Type: application/json" \
  "https://${DOMAIN}.atlassian.net/wiki/rest/api/content/${PAGE_ID}" \
  -d '{
    "version": {"number": NEW_VERSION},
    "title": "Page Title",
    "type": "page",
    "body": {
      "wiki": {
        "value": "# My Page\n\nHere is the diagram:\n\n![Architecture Diagram](architecture.png)\n\nMore content here.",
        "representation": "wiki"
      }
    }
  }'
```

#### Method 2: Storage Format (Direct)

Use native Confluence storage format with `representation: "storage"`:

```bash
curl -u "${EMAIL}:${API_TOKEN}" \
  -X PUT \
  -H "Content-Type: application/json" \
  "https://${DOMAIN}.atlassian.net/wiki/rest/api/content/${PAGE_ID}" \
  -d '{
    "version": {"number": NEW_VERSION},
    "title": "Page Title",
    "type": "page",
    "body": {
      "sto

Related in Backend & APIs