Confluence
name: confluence
by byungkyu · published 2026-03-22
$ claw add gh:byungkyu/byungkyu-confluence-api---
name: confluence
description: |
Confluence API integration with managed OAuth. Manage pages, spaces, blogposts, comments, and attachments.
Use this skill when users want to create, read, update, or delete Confluence content, manage spaces, or work with comments and attachments.
For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).
Requires network access and valid Maton API key.
metadata:
author: maton
version: "1.0"
clawdbot:
emoji: 🧠
homepage: "https://maton.ai"
requires:
env:
- MATON_API_KEY
---
# Confluence
Access the Confluence Cloud API with managed OAuth authentication. Manage pages, spaces, blogposts, comments, attachments, and properties.
Quick Start
# List pages in your Confluence site
python3 <<'EOF'
import urllib.request, os, json
# First get your Cloud ID
req = urllib.request.Request('https://gateway.maton.ai/confluence/oauth/token/accessible-resources')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
resources = json.load(urllib.request.urlopen(req))
cloud_id = resources[0]['id']
# Then list pages
req = urllib.request.Request(f'https://gateway.maton.ai/confluence/ex/confluence/{cloud_id}/wiki/api/v2/pages')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFBase URL
https://gateway.maton.ai/confluence/{atlassian-api-path}Confluence Cloud uses two URL patterns:
**V2 API (recommended):**
https://gateway.maton.ai/confluence/ex/confluence/{cloudId}/wiki/api/v2/{resource}**V1 REST API (limited):**
https://gateway.maton.ai/confluence/ex/confluence/{cloudId}/wiki/rest/api/{resource}The `{cloudId}` is required for all API calls. Obtain it via the accessible-resources endpoint (see below).
Authentication
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY**Environment Variable:** Set your API key as `MATON_API_KEY`:
export MATON_API_KEY="YOUR_API_KEY"Getting Your API Key
1. Sign in or create an account at [maton.ai](https://maton.ai)
2. Go to [maton.ai/settings](https://maton.ai/settings)
3. Copy your API key
Connection Management
Manage your Confluence OAuth connections at `https://ctrl.maton.ai`.
List Connections
python3 <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections?app=confluence&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFCreate Connection
python3 <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'confluence'}).encode()
req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFGet Connection
python3 <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF**Response:**
{
"connection": {
"connection_id": "6cb7787f-7c32-4658-a3c3-4ddf1367a4ce",
"status": "ACTIVE",
"creation_time": "2026-02-13T00:00:00.000000Z",
"last_updated_time": "2026-02-13T00:00:00.000000Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "confluence",
"metadata": {}
}
}Open the returned `url` in a browser to complete OAuth authorization.
Delete Connection
python3 <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFSpecifying Connection
If you have multiple Confluence connections, specify which one to use with the `Maton-Connection` header:
python3 <<'EOF'
import urllib.request, os, json
cloud_id = "YOUR_CLOUD_ID"
req = urllib.request.Request(f'https://gateway.maton.ai/confluence/ex/confluence/{cloud_id}/wiki/api/v2/pages')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '6cb7787f-7c32-4658-a3c3-4ddf1367a4ce')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFIf omitted, the gateway uses the default (oldest) active connection.
Getting Your Cloud ID
Before making API calls, you must obtain your Confluence Cloud ID:
python3 <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/confluence/oauth/token/accessible-resources')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
resources = json.load(urllib.request.urlopen(req))
print(json.dumps(resources, indent=2))
# Use resources[0]['id'] as your cloudId
EOF**Response:**
[
{
"id": "62909843-b784-4c35-b770-e4e2a26f024b",
"name": "your-site-name",
"url": "https://your-site.atlassian.net",
"scopes": ["read:confluence-content.all", "write:confluence-content", ...],
"avatarUrl": "https://..."
}
]API Reference
All V2 API endpoints use the base path:
/confluence/ex/confluence/{cloudId}/wiki/api/v2Pages
#### List Pages
GET /pages
GET /pages?space-id={spaceId}
GET /pages?limit=25
GET /pages?status=current
GET /pages?body-format=storage**Response:**
{
"results": [
{
"id": "98391",
"status": "current",
"title": "My Page",
"spaceId": "98306",
"parentId": "98305",
"parentType": "page",
"authorId": "557058:...",
"createdAt": "2026-02-12T23:00:00.000Z",
"version": {
"number": 1,
"authorId": "557058:...",
"createdAt": "2026-02-12T23:00:00.000Z"
},
"_links": {
"webui": "/spaces/SPACEKEY/pages/98391/My+Page"
}
}
],
"_links": {
"next": "/wiki/api/v2/pages?cursor=..."
}
}#### Get Page
GET /pages/{pageId}
GET /pages/{pageId}?body-format=storage
GET /pages/{pageId}?body-format=atlas_doc_format
GET /pages/{pageId}?body-format=view**Body formats:**
#### Create Page
POST /pages
Content-Type: application/json
{
"spaceId": "98306",
"status": "current",
"title": "New Page Title",
"body": {
"representation": "storage",
"value": "<p>Page content in storage format</p>"
}
}To create a child page, include `parentId`:
{
"spaceId": "98306",
"parentId": "98391",
"status": "current",
"title": "Child Page",
"body": {
"representation": "storage",
"value": "<p>Child page content</p>"
}
}**Response:**
{
"id": "98642",
"status": "current",
"title": "New Page Title",
"spaceId": "98306",
"version": {
"number": 1
}
}#### Update Page
PUT /pages/{pageId}
Content-Type: application/json
{
"id": "98391",
"status": "current",
"title": "Updated Page Title",
"body": {
"representation": "storage",
"value": "<p>Updated content</p>"
},
"version": {
"number": 2,
"message": "Updated via API"
}
}**Note:** You must increment the version number with each update.
#### Delete Page
DELETE /pages/{pageId}Returns `204 No Content` on success.
#### Get Page Children
GET /pages/{pageId}/children#### Get Page Versions
GET /pages/{pageId}/versions#### Get Page Labels
GET /pages/{pageId}/labels#### Get Page Attachments
GET /pages/{pageId}/attachments#### Get Page Comments
GET /pages/{pageId}/footer-comments#### Get Page Properties
GET /pages/{pageId}/properties
GET /pages/{pageId}/properties/{propertyId}#### Create Page Property
POST /pages/{pageId}/properties
Content-Type: application/json
{
"key": "my-property-key",
"value": {"customKey": "customValue"}
}#### Update Page Property
PUT /pages/{pageId}/properties/{propertyId}
Content-Type: application/json
{
"key": "my-property-key",
"value": {"customKey": "updatedValue"},
"version": {"number": 2}
}#### Delete Page Property
DELETE /pages/{pageId}/properties/{propertyId}Spaces
#### List Spaces
GET /spaces
GET /spaces?limit=25
GET /spaces?type=global**Response:**
{
"results": [
{
"id": "98306",
"key": "SPACEKEY",
"name": "Space Name",
"type": "global",
"status": "current",
"authorId": "557058:...",
"createdAt": "2026-02-12T23:00:00.000Z",
"homepageId": "98305",
"_links": {
"webui": "/spaces/SPACEKEY"
}
}
]
}#### Get Space
GET /spaces/{spaceId}#### Get Space Pages
GET /spaces/{spaceId}/pages#### Get Space Blogposts
GET /spaces/{spaceId}/blogposts#### Get Space Properties
GET /spaces/{spaceId}/properties#### Create Space Property
POST /spaces/{spaceId}/properties
Content-Type: application/json
{
"key": "space-property-key",
"value": {"key": "value"}
}#### Get Space Permissions
GET /spaces/{spaceId}/permissions#### Get Space Labels
GET /spaces/{spaceId}/labelsBlogposts
#### List Blogposts
GET /blogposts
GET /blogposts?space-id={spaceId}
GET /blogposts?limit=25#### Get Blogpost
GET /blogposts/{blogpostId}
GET /blogposts/{blogpostId}?body-format=storage#### Create Blogpost
POST /blogposts
Content-Type: application/json
{
"spaceId": "98306",
"title": "My Blog Post",
"body": {
"representation": "storage",
"value": "<p>Blog post content</p>"
}
}#### Update Blogpost
PUT /blogposts/{blogpostId}
Content-Type: application/json
{
"id": "458753",
"status": "current",
"title": "Updated Blog Post",
"body": {
"representation": "storage",
"value": "<p>Updated content</p>"
},
"version": {
"number": 2
}
}#### Delete Blogpost
DELETE /blogposts/{blogpostId}#### Get Blogpost Labels
GET /blogposts/{blogpostId}/labels#### Get Blogpost Versions
GET /blogposts/{blogpostId}/versions#### Get Blogpost Comments
GET /blogposts/{blogpostId}/footer-commentsComments
#### List Footer Comments
GET /footer-comments
GET /footer-comments?body-format=storage#### Get Comment
GET /footer-comments/{commentId}#### Create Footer Comment
POST /footer-comments
Content-Type: application/json
{
"pageId": "98391",
"body": {
"representation": "storage",
"value": "<p>Comment text</p>"
}
}For blogpost comments:
{
"blogpostId": "458753",
"body": {
"representation": "storage",
"value": "<p>Comment on blogpost</p>"
}
}#### Update Comment
PUT /footer-comments/{commentId}
Content-Type: application/json
{
"version": {"number": 2},
"body": {
"representation": "storage",
"value": "<p>Updated comment</p>"
}
}#### Delete Comment
DELETE /footer-comments/{commentId}#### Get Comment Replies
GET /footer-comments/{commentId}/children#### List Inline Comments
GET /inline-commentsAttachments
#### List Attachments
GET /attachments
GET /attachments?limit=25#### Get Attachment
GET /attachments/{attachmentId}#### Get Page Attachments
GET /pages/{pageId}/attachmentsTasks
#### List Tasks
GET /tasks#### Get Task
GET /tasks/{taskId}Labels
#### List Labels
GET /labels
GET /labels?prefix=globalCustom Content
#### List Custom Content
GET /custom-content
GET /custom-content?type={customContentType}User (V1 API)
The current user endpoint uses the V1 REST API:
GET /confluence/ex/confluence/{cloudId}/wiki/rest/api/user/current**Response:**
{
"type": "known",
"accountId": "557058:...",
"accountType": "atlassian",
"email": "user@example.com",
"publicName": "User Name",
"displayName": "User Name"
}Pagination
The V2 API uses cursor-based pagination. Responses include a `_links.next` URL when more results are available.
GET /pages?limit=25**Response:**
{
"results": [...],
"_links": {
"next": "/wiki/api/v2/pages?cursor=eyJpZCI6Ijk4MzkyIn0"
}
}To get the next page, extract the cursor and pass it:
GET /pages?limit=25&cursor=eyJpZCI6Ijk4MzkyIn0Code Examples
JavaScript
// Get Cloud ID first
const resourcesRes = await fetch(
'https://gateway.maton.ai/confluence/oauth/token/accessible-resources',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const resources = await resourcesRes.json();
const cloudId = resources[0].id;
// List pages
const response = await fetch(
`https://gateway.maton.ai/confluence/ex/confluence/${cloudId}/wiki/api/v2/pages`,
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const data = await response.json();Python
import os
import requests
# Get Cloud ID first
resources = requests.get(
'https://gateway.maton.ai/confluence/oauth/token/accessible-resources',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
).json()
cloud_id = resources[0]['id']
# List pages
response = requests.get(
f'https://gateway.maton.ai/confluence/ex/confluence/{cloud_id}/wiki/api/v2/pages',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
)
data = response.json()Notes
Error Handling
| Status | Meaning |
|--------|---------|
| 400 | Bad request or malformed data |
| 401 | Invalid API key or insufficient OAuth scopes |
| 403 | Permission denied |
| 404 | Resource not found |
| 409 | Conflict (e.g., duplicate title) |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from Confluence API |
Troubleshooting: API Key Issues
1. Check that the `MATON_API_KEY` environment variable is set:
echo $MATON_API_KEY2. Verify the API key is valid by listing connections:
python3 <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFTroubleshooting: Invalid App Name
Ensure your URL path starts with `confluence`. For example:
Troubleshooting: Scope Issues
If you receive a 401 error with "scope does not match", you may need to re-authorize with the required scopes. Delete your connection and create a new one:
# Delete existing connection
python3 <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
# Create new connection
python3 <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'confluence'}).encode()
req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFResources
More tools from the same signal band
Order food/drinks (点餐) on an Android device paired as an OpenClaw node. Uses in-app menu and cart; add goods, view cart, submit order (demo, no real payment).
Sign plugins, rotate agent credentials without losing identity, and publicly attest to plugin behavior with verifiable claims and authenticated transfers.
The philosophical layer for AI agents. Maps behavior to Spinoza's 48 affects, calculates persistence scores, and generates geometric self-reports. Give your...