Install
openclaw skills install buffer-apiBuffer API integration with managed authentication. Schedule and manage social media posts across multiple platforms. Use this skill when users want to schedule posts, manage channels, view organizations, or create content ideas in Buffer. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).
openclaw skills install buffer-apiAccess the Buffer GraphQL API with managed authentication. Schedule and manage social media posts across Instagram, Facebook, Twitter, LinkedIn, TikTok, and more.
# Get account info with organizations
python <<'EOF'
import urllib.request, os, json
data = json.dumps({
"query": "query { account { id email organizations { id name } } }"
}).encode()
req = urllib.request.Request('https://api.maton.ai/buffer/', 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
https://api.maton.ai/buffer/
Buffer uses a single GraphQL endpoint. All queries and mutations are sent as POST requests to this endpoint.
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 Buffer connections at https://api.maton.ai.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=buffer&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
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'buffer'}).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
python <<'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-03-12T00:18:28.327860Z",
"last_updated_time": "2026-03-12T00:18:42.818009Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "buffer",
"metadata": {},
"method": "API_KEY"
}
}
python <<'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 Buffer connections, specify which one to use with the Maton-Connection header:
python <<'EOF'
import urllib.request, os, json
data = json.dumps({"query": "query { account { id } }"}).encode()
req = urllib.request.Request('https://api.maton.ai/buffer/', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
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.
python <<'EOF'
import urllib.request, os, json
data = json.dumps({
"query": """
query {
account {
id
email
name
avatar
timezone
createdAt
preferences {
timeFormat
startOfWeek
}
}
}
"""
}).encode()
req = urllib.request.Request('https://api.maton.ai/buffer/', 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
Response:
{
"data": {
"account": {
"id": "69846f7479b75e6487fa3482",
"email": "user@example.com",
"name": "John Doe",
"avatar": "https://...",
"timezone": "America/New_York",
"createdAt": "2024-01-15T10:30:00Z",
"preferences": {
"timeFormat": "12h",
"startOfWeek": "sunday"
}
}
}
}
python <<'EOF'
import urllib.request, os, json
data = json.dumps({
"query": """
query {
account {
organizations {
id
name
channels {
id
name
service
avatar
isDisconnected
}
}
}
}
"""
}).encode()
req = urllib.request.Request('https://api.maton.ai/buffer/', 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
Response:
{
"data": {
"account": {
"organizations": [
{
"id": "69846f7479b75e6487fa3484",
"name": "My Organization",
"channels": [
{
"id": "channel123",
"name": "My Twitter",
"service": "twitter",
"avatar": "https://...",
"isDisconnected": false
}
]
}
]
}
}
}
python <<'EOF'
import urllib.request, os, json
data = json.dumps({
"query": """
query GetChannels($organizationId: OrganizationId!) {
channels(organizationId: $organizationId) {
id
name
service
displayName
avatar
timezone
isDisconnected
isQueuePaused
postingSchedule {
days
times
}
}
}
""",
"variables": {
"organizationId": "69846f7479b75e6487fa3484"
}
}).encode()
req = urllib.request.Request('https://api.maton.ai/buffer/', 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
python <<'EOF'
import urllib.request, os, json
data = json.dumps({
"query": """
query GetChannel($channelId: ChannelId!) {
channel(channelId: $channelId) {
id
name
service
displayName
avatar
timezone
postingSchedule {
days
times
}
postingGoal {
postsPerWeek
progress
}
}
}
""",
"variables": {
"channelId": "channel123"
}
}).encode()
req = urllib.request.Request('https://api.maton.ai/buffer/', 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
python <<'EOF'
import urllib.request, os, json
data = json.dumps({
"query": """
query GetPosts($channelId: ChannelId!, $status: PostStatus, $first: Int) {
posts(channelId: $channelId, status: $status, first: $first) {
edges {
node {
id
text
status
createdAt
dueAt
sentAt
channelService
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
""",
"variables": {
"channelId": "channel123",
"status": "scheduled",
"first": 10
}
}).encode()
req = urllib.request.Request('https://api.maton.ai/buffer/', 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
Post Status Values:
draft - Saved as draftscheduled - Scheduled for publishingsent - Publishedfailed - Failed to publishpython <<'EOF'
import urllib.request, os, json
data = json.dumps({
"query": """
query GetPost($postId: PostId!) {
post(id: $postId) {
id
text
status
createdAt
dueAt
sentAt
author {
name
email
}
channel {
id
name
service
}
assets {
id
url
type
}
}
}
""",
"variables": {
"postId": "post123"
}
}).encode()
req = urllib.request.Request('https://api.maton.ai/buffer/', 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
python <<'EOF'
import urllib.request, os, json
data = json.dumps({
"query": """
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
... on Post {
id
text
status
dueAt
}
... on InvalidInputError {
message
}
... on UnauthorizedError {
message
}
}
}
""",
"variables": {
"input": {
"channelId": "channel123",
"text": "Hello from Buffer API!",
"schedulingType": "scheduled",
"dueAt": "2026-03-15T14:00:00Z",
"mode": "queue"
}
}
}).encode()
req = urllib.request.Request('https://api.maton.ai/buffer/', 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
CreatePostInput Fields:
channelId (required): Target channel IDtext: Post contentschedulingType (required): "scheduled", "draft", or "now"dueAt: ISO 8601 datetime for scheduled postsmode (required): "queue" or "share"assets: Media attachmentstagIds: Content tagsmetadata: Platform-specific options (see Platform Metadata section)ideaId: Link post to existing ideadraftId: Create from existing draftsource: Origin of postaiAssisted: Whether AI helped create contentsaveToDraft: Save as draft instead of schedulingpython <<'EOF'
import urllib.request, os, json
data = json.dumps({
"query": """
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
... on Post { id text status }
... on InvalidInputError { message }
}
}
""",
"variables": {
"input": {
"channelId": "instagram_channel_id",
"text": "Check out our latest post! #photography",
"schedulingType": "scheduled",
"dueAt": "2026-03-15T14:00:00Z",
"mode": "queue",
"metadata": {
"instagram": {
"type": "post",
"firstComment": "Follow us for more!",
"shouldShareToFeed": True
}
}
}
}
}).encode()
req = urllib.request.Request('https://api.maton.ai/buffer/', 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
python <<'EOF'
import urllib.request, os, json
data = json.dumps({
"query": """
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
... on Post { id text status }
... on InvalidInputError { message }
}
}
""",
"variables": {
"input": {
"channelId": "twitter_channel_id",
"text": "First tweet in thread",
"schedulingType": "scheduled",
"dueAt": "2026-03-15T14:00:00Z",
"mode": "queue",
"metadata": {
"twitter": {
"thread": [
{"text": "Second tweet in thread"},
{"text": "Third tweet in thread"}
]
}
}
}
}
}).encode()
req = urllib.request.Request('https://api.maton.ai/buffer/', 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
python <<'EOF'
import urllib.request, os, json
data = json.dumps({
"query": """
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
... on Post { id text status }
... on InvalidInputError { message }
}
}
""",
"variables": {
"input": {
"channelId": "linkedin_channel_id",
"text": "Check out our latest blog post!",
"schedulingType": "scheduled",
"dueAt": "2026-03-15T14:00:00Z",
"mode": "queue",
"metadata": {
"linkedin": {
"linkAttachment": {
"url": "https://example.com/blog-post",
"title": "Our Latest Blog Post",
"description": "Read about our new features"
},
"firstComment": "What do you think?"
}
}
}
}
}).encode()
req = urllib.request.Request('https://api.maton.ai/buffer/', 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
python <<'EOF'
import urllib.request, os, json
data = json.dumps({
"query": """
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
... on Post { id text status }
... on InvalidInputError { message }
}
}
""",
"variables": {
"input": {
"channelId": "pinterest_channel_id",
"text": "Beautiful sunset photo",
"schedulingType": "scheduled",
"dueAt": "2026-03-15T14:00:00Z",
"mode": "queue",
"metadata": {
"pinterest": {
"title": "Amazing Sunset",
"url": "https://example.com/sunset",
"boardServiceId": "board_id"
}
}
}
}
}).encode()
req = urllib.request.Request('https://api.maton.ai/buffer/', 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
python <<'EOF'
import urllib.request, os, json
data = json.dumps({
"query": """
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
... on Post { id text status }
... on InvalidInputError { message }
}
}
""",
"variables": {
"input": {
"channelId": "youtube_channel_id",
"text": "Video description here",
"schedulingType": "scheduled",
"dueAt": "2026-03-15T14:00:00Z",
"mode": "queue",
"metadata": {
"youtube": {
"title": "My Video Title",
"privacy": "public",
"categoryId": "22",
"notifySubscribers": True,
"embeddable": True,
"madeForKids": False
}
}
}
}
}).encode()
req = urllib.request.Request('https://api.maton.ai/buffer/', 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
python <<'EOF'
import urllib.request, os, json
data = json.dumps({
"query": """
mutation CreateIdea($input: CreateIdeaInput!) {
createIdea(input: $input) {
... on Idea {
id
title
text
createdAt
}
... on InvalidInputError {
message
}
}
}
""",
"variables": {
"input": {
"organizationId": "69846f7479b75e6487fa3484",
"title": "Blog post idea",
"text": "Write about social media best practices",
"services": ["twitter", "linkedin"]
}
}
}).encode()
req = urllib.request.Request('https://api.maton.ai/buffer/', 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
| Field | Type | Description |
|---|---|---|
id | ID | Account identifier |
email | String | Primary email |
backupEmail | String | Backup email address |
name | String | Display name |
avatar | String | Avatar URL |
timezone | String | User timezone |
createdAt | DateTime | Account creation date |
organizations | [Organization] | Organizations the user belongs to |
preferences | Preferences | User preferences (timeFormat, startOfWeek) |
connectedApps | [ConnectedApp] | Third-party app connections |
| Field | Type | Description |
|---|---|---|
id | ID | Organization identifier |
name | String | Organization name |
ownerEmail | String | Owner's email |
channelCount | Int | Number of connected channels |
channels | [Channel] | Connected social channels |
members | [Member] | Team members |
limits | Limits | Plan limits and usage |
| Field | Type | Description |
|---|---|---|
id | ID | Channel identifier |
name | String | Channel name |
displayName | String | Display name |
service | String | Platform (twitter, instagram, etc.) |
serviceId | String | Platform-specific ID |
type | String | Channel type |
avatar | String | Channel avatar URL |
timezone | String | Channel timezone |
isDisconnected | Boolean | Connection status |
isLocked | Boolean | Lock status |
isNew | Boolean | Recently added |
isQueuePaused | Boolean | Queue paused status |
postingSchedule | PostingSchedule | Scheduled posting times (days, times) |
postingGoal | PostingGoal | Weekly posting goal (postsPerWeek, progress) |
weeklyPostingLimit | Int | Maximum posts per week |
allowedActions | [String] | Permitted actions |
scopes | [String] | OAuth scopes |
products | [String] | Enabled products |
externalLink | String | Link to profile |
linkShortening | LinkShortening | URL shortening settings |
hasActiveMemberDevice | Boolean | Mobile app connected |
showTrendingTopicSuggestions | Boolean | Show trending suggestions |
metadata | ChannelMetadata | Platform-specific metadata |
organizationId | ID | Parent organization |
createdAt | DateTime | Creation date |
updatedAt | DateTime | Last update |
| Field | Type | Description |
|---|---|---|
id | ID | Post identifier |
text | String | Post content |
status | PostStatus | draft, scheduled, sent, failed |
schedulingType | String | scheduled, draft, now |
dueAt | DateTime | Scheduled publish time |
sentAt | DateTime | Actual publish time |
createdAt | DateTime | Creation time |
updatedAt | DateTime | Last update time |
author | Author | Post creator (name, email) |
channel | Channel | Target channel |
channelId | ID | Channel identifier |
channelService | String | Platform name |
ideaId | ID | Linked idea |
via | String | Creation source |
isCustomScheduled | Boolean | Custom scheduled time |
externalLink | String | Link to published post |
assets | [Asset] | Media attachments (id, url, type) |
tags | [Tag] | Content tags |
notes | [Note] | Internal notes |
metadata | PostMetadata | Platform-specific options |
notificationStatus | String | Notification state |
error | PostError | Error details if failed |
allowedActions | [String] | Permitted actions |
sharedNow | Boolean | Posted immediately |
shareMode | String | Sharing mode |
| Field | Type | Description |
|---|---|---|
id | ID | Idea identifier |
organizationId | ID | Parent organization |
content | IdeaContent | Title, text, services |
groupId | ID | Idea group |
position | Int | Order in group |
createdAt | DateTime | Creation date |
updatedAt | DateTime | Last update |
| Field | Type | Description |
|---|---|---|
type | String | post, story, reel |
firstComment | String | Auto-comment after posting |
link | String | Link in bio reference |
geolocation | Geolocation | Location tag |
shouldShareToFeed | Boolean | Share reel to feed |
stickerFields | StickerFields | Story stickers |
| Field | Type | Description |
|---|---|---|
type | String | Post type |
annotations | [Annotation] | Tags and mentions |
linkAttachment | LinkAttachment | Link preview (url, title, description) |
firstComment | String | Auto-comment |
title | String | Post title |
| Field | Type | Description |
|---|---|---|
annotations | [Annotation] | Tags and mentions |
linkAttachment | LinkAttachment | Link preview |
firstComment | String | Auto-comment |
| Field | Type | Description |
|---|---|---|
retweet | RetweetInput | Quote retweet settings |
thread | [ThreadItem] | Thread tweets [{text}] |
| Field | Type | Description |
|---|---|---|
title | String | Pin title |
url | String | Destination URL |
boardServiceId | String | Target board ID |
| Field | Type | Description |
|---|---|---|
title | String | Video title |
privacy | String | public, unlisted, private |
categoryId | String | YouTube category ID |
license | String | Video license |
notifySubscribers | Boolean | Send notifications |
embeddable | Boolean | Allow embedding |
madeForKids | Boolean | Kids content flag |
| Field | Type | Description |
|---|---|---|
title | String | Video title |
| Field | Type | Description |
|---|---|---|
type | String | Post type |
title | String | Post title |
detailsOffer | OfferDetails | Offer details |
detailsEvent | EventDetails | Event details |
detailsWhatsNew | WhatsNewDetails | Update details |
| Field | Type | Description |
|---|---|---|
thread | [ThreadItem] | Thread toots |
spoilerText | String | Content warning |
| Field | Type | Description |
|---|---|---|
type | String | Post type |
thread | [ThreadItem] | Thread posts |
linkAttachment | LinkAttachment | Link preview |
topic | String | Topic tag |
locationId | String | Location ID |
locationName | String | Location name |
| Field | Type | Description |
|---|---|---|
thread | [ThreadItem] | Thread skeets |
linkAttachment | LinkAttachment | Link card |
Buffer supports posting to:
Posts use cursor-based pagination:
python <<'EOF'
import urllib.request, os, json
data = json.dumps({
"query": """
query GetPosts($channelId: ChannelId!, $first: Int, $after: String) {
posts(channelId: $channelId, first: $first, after: $after) {
edges {
node {
id
text
}
cursor
}
pageInfo {
hasNextPage
endCursor
}
}
}
""",
"variables": {
"channelId": "channel123",
"first": 10,
"after": "cursor_from_previous_page"
}
}).encode()
req = urllib.request.Request('https://api.maton.ai/buffer/', 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
const response = await fetch('https://api.maton.ai/buffer/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
},
body: JSON.stringify({
query: `query { account { id email organizations { id name } } }`
})
});
const data = await response.json();
console.log(data.data.account);
import os
import requests
response = requests.post(
'https://api.maton.ai/buffer/',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'},
json={
'query': 'query { account { id email organizations { id name } } }'
}
)
data = response.json()
print(data['data']['account'])
jq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments| Status | Meaning |
|---|---|
| 400 | Missing Buffer connection or invalid GraphQL query |
| 401 | Invalid or missing Maton API key |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from Buffer API |
GraphQL Error Types:
InvalidInputError - Invalid mutation inputNotFoundError - Resource not foundUnauthorizedError - Insufficient permissionsLimitReachedError - Plan limits exceededMATON_API_KEY environment variable is set:echo $MATON_API_KEY
python <<'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
buffer. For example:https://api.maton.ai/buffer/https://api.maton.ai/graphql