From 100f85e990e16483e83916642e8c80c01f85cf1a Mon Sep 17 00:00:00 2001 From: Christian Gick Date: Mon, 2 Mar 2026 14:13:06 +0200 Subject: [PATCH] fix: use Confluence v2 API for page creation (v1 returns 410 Gone) Switch from /wiki/rest/api/content to /wiki/api/v2/pages. V2 requires space ID instead of key, so resolve via /api/v2/spaces first. Co-Authored-By: Claude Opus 4.6 --- bot.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/bot.py b/bot.py index 6925c8a..86f257c 100644 --- a/bot.py +++ b/bot.py @@ -651,18 +651,31 @@ class AtlassianClient: if not cloud_id: return "Error: Could not determine Atlassian Cloud instance." try: - paragraphs = [p.strip() for p in content.split("\n") if p.strip()] - body_html = "".join(f"

{p}

" for p in paragraphs) if paragraphs else f"

{content}

" + headers = {"Authorization": f"Bearer {token}"} async with httpx.AsyncClient(timeout=15.0) as client: + # Resolve space key to space ID (v2 API requires ID) + space_resp = await client.get( + f"https://api.atlassian.com/ex/confluence/{cloud_id}/wiki/api/v2/spaces", + params={"keys": space_key}, + headers=headers, + ) + space_resp.raise_for_status() + spaces = space_resp.json().get("results", []) + if not spaces: + return f"Space '{space_key}' not found." + space_id = spaces[0]["id"] + + paragraphs = [p.strip() for p in content.split("\n") if p.strip()] + body_html = "".join(f"

{p}

" for p in paragraphs) if paragraphs else f"

{content}

" resp = await client.post( - f"https://api.atlassian.com/ex/confluence/{cloud_id}/wiki/rest/api/content", + f"https://api.atlassian.com/ex/confluence/{cloud_id}/wiki/api/v2/pages", json={ - "type": "page", + "spaceId": space_id, + "status": "current", "title": title, - "space": {"key": space_key}, - "body": {"storage": {"value": body_html, "representation": "storage"}}, + "body": {"representation": "storage", "value": body_html}, }, - headers={"Authorization": f"Bearer {token}"}, + headers=headers, ) resp.raise_for_status() data = resp.json()