Install
openclaw skills install confluence-apiConfluence 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.
openclaw skills install confluence-apiAccess the Confluence Cloud API with managed OAuth authentication. Manage pages, spaces, blogposts, comments, attachments, and properties.
# List pages in your Confluence site
python3 <<'EOF'
import urllib.request, os, json
# First get your Cloud ID
req = urllib.request.Request('https://api.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://api.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))
EOF
https://api.maton.ai/confluence/{atlassian-api-path}
Confluence Cloud uses two URL patterns:
V2 API (recommended):
https://api.maton.ai/confluence/ex/confluence/{cloudId}/wiki/api/v2/{resource}
V1 REST API (limited):
https://api.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).
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"
Manage your Confluence OAuth connections at https://api.maton.ai.
python3 <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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))
EOF
python3 <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'confluence'}).encode()
req = urllib.request.Request('https://api.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))
EOF
python3 <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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": "{connection_id}",
"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.
python3 <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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
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://api.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', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple connections, always include this header to ensure requests go to the intended account.
Before making API calls, you must obtain your Confluence Cloud ID:
python3 <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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://..."
}
]
All V2 API endpoints use the base path:
/confluence/ex/confluence/{cloudId}/wiki/api/v2
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 /pages/{pageId}
GET /pages/{pageId}?body-format=storage
GET /pages/{pageId}?body-format=atlas_doc_format
GET /pages/{pageId}?body-format=view
Body formats:
storage - Confluence storage format (XML-like)atlas_doc_format - Atlassian Document Format (JSON)view - Rendered HTMLPOST /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
}
}
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 /pages/{pageId}
Returns 204 No Content on success.
GET /pages/{pageId}/children
GET /pages/{pageId}/versions
GET /pages/{pageId}/labels
GET /pages/{pageId}/attachments
GET /pages/{pageId}/footer-comments
GET /pages/{pageId}/properties
GET /pages/{pageId}/properties/{propertyId}
POST /pages/{pageId}/properties
Content-Type: application/json
{
"key": "my-property-key",
"value": {"customKey": "customValue"}
}
PUT /pages/{pageId}/properties/{propertyId}
Content-Type: application/json
{
"key": "my-property-key",
"value": {"customKey": "updatedValue"},
"version": {"number": 2}
}
DELETE /pages/{pageId}/properties/{propertyId}
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 /spaces/{spaceId}
GET /spaces/{spaceId}/pages
GET /spaces/{spaceId}/blogposts
GET /spaces/{spaceId}/properties
POST /spaces/{spaceId}/properties
Content-Type: application/json
{
"key": "space-property-key",
"value": {"key": "value"}
}
GET /spaces/{spaceId}/permissions
GET /spaces/{spaceId}/labels
GET /blogposts
GET /blogposts?space-id={spaceId}
GET /blogposts?limit=25
GET /blogposts/{blogpostId}
GET /blogposts/{blogpostId}?body-format=storage
POST /blogposts
Content-Type: application/json
{
"spaceId": "98306",
"title": "My Blog Post",
"body": {
"representation": "storage",
"value": "<p>Blog post content</p>"
}
}
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 /blogposts/{blogpostId}
GET /blogposts/{blogpostId}/labels
GET /blogposts/{blogpostId}/versions
GET /blogposts/{blogpostId}/footer-comments
GET /footer-comments
GET /footer-comments?body-format=storage
GET /footer-comments/{commentId}
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>"
}
}
PUT /footer-comments/{commentId}
Content-Type: application/json
{
"version": {"number": 2},
"body": {
"representation": "storage",
"value": "<p>Updated comment</p>"
}
}
DELETE /footer-comments/{commentId}
GET /footer-comments/{commentId}/children
GET /inline-comments
GET /attachments
GET /attachments?limit=25
GET /attachments/{attachmentId}
GET /pages/{pageId}/attachments
GET /tasks
GET /tasks/{taskId}
GET /labels
GET /labels?prefix=global
GET /custom-content
GET /custom-content?type={customContentType}
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"
}
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=eyJpZCI6Ijk4MzkyIn0
// Get Cloud ID first
const resourcesRes = await fetch(
'https://api.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://api.maton.ai/confluence/ex/confluence/${cloudId}/wiki/api/v2/pages`,
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const data = await response.json();
import os
import requests
# Get Cloud ID first
resources = requests.get(
'https://api.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://api.maton.ai/confluence/ex/confluence/{cloud_id}/wiki/api/v2/pages',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
)
data = response.json()
/oauth/token/accessible-resources before making API calls/wiki/api/v2/) for most operations. The V1 API (/wiki/rest/api/) is limitedstorage format for creating/updating content. Use view for rendered HTML<p>Paragraph</p>, <h1>Heading</h1>jq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments| 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 |
MATON_API_KEY environment variable is set:echo $MATON_API_KEY
python3 <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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))
EOF
Ensure your URL path starts with confluence. For example:
https://api.maton.ai/confluence/ex/confluence/{cloudId}/wiki/api/v2/pageshttps://api.maton.ai/ex/confluence/{cloudId}/wiki/api/v2/pagesIf 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://api.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://api.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))
EOF