- name
- confluence
- description
- |
- metadata
- author
- maton
- version
- 1.0
- clawdbot
- emoji
- 🧠
- homepage
- https://maton.ai
- requires
- env
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://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))
EOFBase URL
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).
Authentication
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:
export MATON_API_KEY="YOUR_API_KEY"Getting Your API Key
- Sign in or create an account at maton.ai
- Go to maton.ai/settings
- Copy your API key
Connection Management
Manage your Confluence OAuth connections at https://api.maton.ai.
List Connections
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))
EOFCreate 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))
EOFGet Connection
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))
EOFResponse:
{
"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.
Delete 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))
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://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))
EOFIf you have multiple connections, always include this header to ensure requests go to the intended account.
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://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
EOFResponse:
[
{
"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://..."
}
]Security & Permissions
- Access is scoped to pages, spaces, blogposts, comments, and attachments within the connected Confluence account.
- All write operations require explicit user approval. Before executing any create, update, or delete call, confirm the target resource and intended effect with the user.
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=storageResponse:
{
"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=viewBody formats:
storage- Confluence storage format (XML-like)atlas_doc_format- Atlassian Document Format (JSON)view- Rendered HTML
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}/childrenGet Page Versions
GET /pages/{pageId}/versionsGet Page Labels
GET /pages/{pageId}/labelsGet Page Attachments
GET /pages/{pageId}/attachmentsGet Page Comments
GET /pages/{pageId}/footer-commentsGet 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=globalResponse:
{
"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}/pagesGet Space Blogposts
GET /spaces/{spaceId}/blogpostsGet Space Properties
GET /spaces/{spaceId}/propertiesCreate Space Property
POST /spaces/{spaceId}/properties
Content-Type: application/json
{
"key": "space-property-key",
"value": {"key": "value"}
}Get Space Permissions
GET /spaces/{spaceId}/permissionsGet Space Labels
GET /spaces/{spaceId}/labelsBlogposts
List Blogposts
GET /blogposts
GET /blogposts?space-id={spaceId}
GET /blogposts?limit=25Get Blogpost
GET /blogposts/{blogpostId}
GET /blogposts/{blogpostId}?body-format=storageCreate 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}/labelsGet Blogpost Versions
GET /blogposts/{blogpostId}/versionsGet Blogpost Comments
GET /blogposts/{blogpostId}/footer-commentsComments
List Footer Comments
GET /footer-comments
GET /footer-comments?body-format=storageGet 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}/childrenList Inline Comments
GET /inline-commentsAttachments
List Attachments
GET /attachments
GET /attachments?limit=25Get Attachment
GET /attachments/{attachmentId}Get Page Attachments
GET /pages/{pageId}/attachmentsTasks
List Tasks
GET /tasksGet 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/currentResponse:
{
"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=25Response:
{
"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://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();Python
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()Notes
- Cloud ID Required: You must obtain your Cloud ID via
/oauth/token/accessible-resourcesbefore making API calls - V2 API Recommended: Use the V2 API (
/wiki/api/v2/) for most operations. The V1 API (/wiki/rest/api/) is limited - Body Formats: Use
storageformat for creating/updating content. Useviewfor rendered HTML - Version Numbers: When updating pages or blogposts, you must increment the version number
- Storage Format: Content uses Confluence storage format (XML-like). Example:
<p>Paragraph</p>,<h1>Heading</h1> - Delete Returns 204: DELETE operations return 204 No Content with no response body
- IDs are Strings: Page, space, and other IDs should be passed as strings
- IMPORTANT: When piping curl output to
jqor other commands, environment variables like$MATON_API_KEYmay not expand correctly in some shell environments
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
- Check that the
MATON_API_KEYenvironment variable is set:
echo $MATON_API_KEY- Verify the API key is valid by listing connections:
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))
EOFTroubleshooting: Invalid App Name
Ensure your URL path starts with confluence. For example:
- Correct:
https://api.maton.ai/confluence/ex/confluence/{cloudId}/wiki/api/v2/pages - Incorrect:
https://api.maton.ai/ex/confluence/{cloudId}/wiki/api/v2/pages
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://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