Install any skill in seconds. Free to start, no credit card required.
Get Started Free →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.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-09 | ✗→✓ | ▲ Improved | 243% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 303% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 274% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 855% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 340% | 0% |
Access the Confluence Cloud API with managed OAuth authentication. Manage pages, spaces, blogposts, comments, attachments, and properties.
bash# 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)) EOF
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).
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEYEnvironment Variable: Set your API key as MATON_API_KEY:
bashexport MATON_API_KEY="YOUR_API_KEY"
Manage your Confluence OAuth connections at https://ctrl.maton.ai.
bashpython3 <<'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)) EOF
bashpython3 <<'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)) EOF
bashpython3 <<'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:
json{ "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.
bashpython3 <<'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
If you have multiple Confluence connections, specify which one to use with the Maton-Connection header:
bashpython3 <<'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)) EOF
If omitted, the gateway uses the default (oldest) active connection.
Before making API calls, you must obtain your Confluence Cloud ID:
bashpython3 <<'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:
json[ { "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/v2bashGET /pages GET /pages?space-id={spaceId} GET /pages?limit=25 GET /pages?status=current GET /pages?body-format=storage
Response:
json{ "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=..." } }
bashGET /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 HTMLbashPOST /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:
json{ "spaceId": "98306", "parentId": "98391", "status": "current", "title": "Child Page", "body": { "representation": "storage", "value": "<p>Child page content</p>" } }
Response:
json{ "id": "98642", "status": "current", "title": "New Page Title", "spaceId": "98306", "version": { "number": 1 } }
bashPUT /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.
bashDELETE /pages/{pageId}
Returns 204 No Content on success.
bashGET /pages/{pageId}/children
bashGET /pages/{pageId}/versions
bashGET /pages/{pageId}/labels
bashGET /pages/{pageId}/attachments
bashGET /pages/{pageId}/footer-comments
bashGET /pages/{pageId}/properties GET /pages/{pageId}/properties/{propertyId}
bashPOST /pages/{pageId}/properties Content-Type: application/json { "key": "my-property-key", "value": {"customKey": "customValue"} }
bashPUT /pages/{pageId}/properties/{propertyId} Content-Type: application/json { "key": "my-property-key", "value": {"customKey": "updatedValue"}, "version": {"number": 2} }
bashDELETE /pages/{pageId}/properties/{propertyId}
bashGET /spaces GET /spaces?limit=25 GET /spaces?type=global
Response:
json{ "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" } } ] }
bashGET /spaces/{spaceId}
bashGET /spaces/{spaceId}/pages
bashGET /spaces/{spaceId}/blogposts
bashGET /spaces/{spaceId}/properties
bashPOST /spaces/{spaceId}/properties Content-Type: application/json { "key": "space-property-key", "value": {"key": "value"} }
bashGET /spaces/{spaceId}/permissions
bashGET /spaces/{spaceId}/labels
bashGET /blogposts GET /blogposts?space-id={spaceId} GET /blogposts?limit=25
bashGET /blogposts/{blogpostId} GET /blogposts/{blogpostId}?body-format=storage
bashPOST /blogposts Content-Type: application/json { "spaceId": "98306", "title": "My Blog Post", "body": { "representation": "storage", "value": "<p>Blog post content</p>" } }
bashPUT /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 } }
bashDELETE /blogposts/{blogpostId}
bashGET /blogposts/{blogpostId}/labels
bashGET /blogposts/{blogpostId}/versions
bashGET /blogposts/{blogpostId}/footer-comments
bashGET /footer-comments GET /footer-comments?body-format=storage
bashGET /footer-comments/{commentId}
bashPOST /footer-comments Content-Type: application/json { "pageId": "98391", "body": { "representation": "storage", "value": "<p>Comment text</p>" } }
For blogpost comments:
json{ "blogpostId": "458753", "body": { "representation": "storage", "value": "<p>Comment on blogpost</p>" } }
bashPUT /footer-comments/{commentId} Content-Type: application/json { "version": {"number": 2}, "body": { "representation": "storage", "value": "<p>Updated comment</p>" } }
bashDELETE /footer-comments/{commentId}
bashGET /footer-comments/{commentId}/children
bashGET /inline-comments
bashGET /attachments GET /attachments?limit=25
bashGET /attachments/{attachmentId}
bashGET /pages/{pageId}/attachments
bashGET /tasks
bashGET /tasks/{taskId}
bashGET /labels GET /labels?prefix=global
bashGET /custom-content GET /custom-content?type={customContentType}
The current user endpoint uses the V1 REST API:
bashGET /confluence/ex/confluence/{cloudId}/wiki/rest/api/user/current
Response:
json{ "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.
bashGET /pages?limit=25
Response:
json{ "results": [...], "_links": { "next": "/wiki/api/v2/pages?cursor=eyJpZCI6Ijk4MzkyIn0" } }
To get the next page, extract the cursor and pass it:
bashGET /pages?limit=25&cursor=eyJpZCI6Ijk4MzkyIn0
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();
pythonimport 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()
/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:bashecho $MATON_API_KEY
bashpython3 <<'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)) EOF
Ensure your URL path starts with confluence. For example:
https://gateway.maton.ai/confluence/ex/confluence/{cloudId}/wiki/api/v2/pageshttps://gateway.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:
bash# 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)) EOF
Other measured skills in the registry, with their headline benchmark lift.