buffer
Original:🇺🇸 English
Translated
This skill should be used when interfacing with the Buffer social media scheduling API. It handles scheduling social media posts, checking the queue, listing channels, creating ideas, and managing Buffer accounts.
6installs
Sourcedgalarza/agent-skills
Added on
NPX Install
npx skill4agent add dgalarza/agent-skills bufferTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Buffer Social Media Scheduling
Setup
Requires a environment variable. Generate one at:
https://publish.buffer.com/settings/api
BUFFER_API_TOKENVerify the token is set before making any API calls:
bash
if [ -z "$BUFFER_API_TOKEN" ]; then
echo "Error: BUFFER_API_TOKEN is not set. Get your token at https://publish.buffer.com/settings/api"
exit 1
fiAPI Configuration
- Endpoint:
https://api.buffer.com - Method: POST (all requests are GraphQL)
- Content-Type:
application/json - Auth:
Authorization: Bearer $BUFFER_API_TOKEN - User-Agent: — required to avoid Cloudflare 403 blocks
Mozilla/5.0
Curl Template
All API calls follow this pattern:
bash
curl -s -X POST https://api.buffer.com \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BUFFER_API_TOKEN" \
-H "User-Agent: Mozilla/5.0" \
-d '{"query": "<GRAPHQL_QUERY>", "variables": <VARIABLES_JSON>}'Always pipe through for readable output. Use to detect errors.
jqjq -eImportant: For queries with GraphQL variables (e.g. ), the shell may expand even inside single quotes. Use a temp file with to avoid this:
$input$input-d @filebash
cat > /tmp/buffer_payload.json << 'EOF'
{"query": "<GRAPHQL_QUERY>", "variables": <VARIABLES_JSON>}
EOF
curl -s -X POST https://api.buffer.com \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BUFFER_API_TOKEN" \
-H "User-Agent: Mozilla/5.0" \
-d @/tmp/buffer_payload.json | jq .Simple queries without variables can use inline directly.
-dMode Detection
Parse the user's intent to determine which operation to perform:
| Intent | Mode | Example |
|---|---|---|
| List organizations | | "Show my Buffer organizations" |
| List channels | | "What channels do I have?" |
| View posts | | "Show my scheduled posts" |
| Create a text post | | "Schedule a tweet saying..." |
| Create a Twitter/X thread | | "Post a thread on X..." |
| Create an image post | | "Post this image to Instagram" |
| Save an idea | | "Save an idea about..." |
| Account info | | "Show my Buffer account" |
Most operations require an . If the user hasn't specified one, fetch organizations first. If only one org exists, use it automatically.
organizationIdMode: Get Organizations
Fetch the user's organizations. This is typically the first call needed.
bash
curl -s -X POST https://api.buffer.com \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BUFFER_API_TOKEN" \
-H "User-Agent: Mozilla/5.0" \
-d '{"query": "{ account { organizations { id name ownerEmail } } }"}' | jq .Store the from the response for subsequent calls.
organizationIdMode: Get Channels
List channels (social media accounts) for an organization.
bash
cat > /tmp/buffer_payload.json << 'EOF'
{"query": "query GetChannels($input: ChannelsInput!) { channels(input: $input) { id name displayName service avatar isQueuePaused } }", "variables": {"input": {"organizationId": "<ORG_ID>"}}}
EOF
curl -s -X POST https://api.buffer.com \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BUFFER_API_TOKEN" \
-H "User-Agent: Mozilla/5.0" \
-d @/tmp/buffer_payload.json | jq .Display results in a readable format showing channel name, service (e.g., twitter, instagram, linkedin), and queue status.
Mode: Get Posts
Query posts with filtering, sorting, and pagination.
bash
cat > /tmp/buffer_payload.json << 'EOF'
{"query": "query GetPosts($input: PostsInput!) { posts(input: $input) { edges { node { id text status dueAt sentAt createdAt channelService externalLink } cursor } pageInfo { hasNextPage endCursor } totalCount } }", "variables": {"input": {"organizationId": "<ORG_ID>", "filter": {"status": "scheduled"}, "sort": {"field": "dueAt", "direction": "desc"}}}}
EOF
curl -s -X POST https://api.buffer.com \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BUFFER_API_TOKEN" \
-H "User-Agent: Mozilla/5.0" \
-d @/tmp/buffer_payload.json | jq .For available filter fields (status, channelIds, date range), sort options, and pagination details, refer to .
references/api-reference.mdMode: Create Text Post
Create and schedule a text post.
bash
cat > /tmp/buffer_payload.json << 'EOF'
{"query": "mutation CreatePost($input: CreatePostInput!) { createPost(input: $input) { ... on PostActionSuccess { post { id text status dueAt } } ... on MutationError { message } } }", "variables": {"input": {"channelId": "<CHANNEL_ID>", "text": "<POST_CONTENT>", "schedulingType": "automatic", "mode": "addToQueue"}}}
EOF
curl -s -X POST https://api.buffer.com \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BUFFER_API_TOKEN" \
-H "User-Agent: Mozilla/5.0" \
-d @/tmp/buffer_payload.json | jq .Required Fields
- channelId (String!): The channel to post to
- text (String!): The post content
Scheduling Options
- schedulingType: (Buffer picks time) or
automatic(sends reminder)notification - mode: Controls when the post is published (e.g., ,
addToQueue,shareNow,shareNext,customSchedule)recommendedTime - dueAt (String): ISO 8601 datetime, required when mode is . Example:
customSchedule"2026-03-15T14:00:00Z"
For full field definitions and enum values, refer to .
references/api-reference.mdResponse Handling
The mutation returns a union type. Always check for both success and error:
bash
# Check if the response contains an error
result=$(curl -s -X POST https://api.buffer.com -H "User-Agent: Mozilla/5.0" ...)
echo "$result" | jq -e '.data.createPost.message' > /dev/null 2>&1 && {
echo "Error: $(echo "$result" | jq -r '.data.createPost.message')"
} || {
echo "$result" | jq '.data.createPost.post'
}Mode: Create Twitter/X Thread
Twitter/X threads are created using the field on the mutation. The thread is an array of objects, each with a field (and optional ).
metadata.twitter.threadcreatePostThreadedPostInputtextassetsImportant: The first tweet in the thread must be included in the array. The top-level field is also required but Buffer uses the thread array to render all tweets in its UI. Include the same text in both places for the first tweet.
threadtextbash
cat > /tmp/buffer_payload.json << 'EOF'
{"query": "mutation CreatePost($input: CreatePostInput!) { createPost(input: $input) { ... on PostActionSuccess { post { id text status dueAt } } ... on MutationError { message } } }", "variables": {"input": {"channelId": "<CHANNEL_ID>", "text": "<FIRST_TWEET_TEXT>", "schedulingType": "automatic", "mode": "addToQueue", "metadata": {"twitter": {"thread": [{"text": "<FIRST_TWEET_TEXT>"}, {"text": "<SECOND_TWEET_TEXT>"}, {"text": "<THIRD_TWEET_TEXT>"}]}}}}}
EOF
curl -s -X POST https://api.buffer.com \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BUFFER_API_TOKEN" \
-H "User-Agent: Mozilla/5.0" \
-d @/tmp/buffer_payload.json | jq .Thread Structure
- Top-level : Required. Use the first tweet's text.
text - : Array of
metadata.twitter.threadobjects. Each has:ThreadedPostInput- (String): The tweet content
text - (AssetsInput, optional): Images for that specific tweet
assets
- The first entry in the array should match the top-level
thread(this is what Buffer displays as tweet 1).text - All subsequent entries become reply tweets in the thread.
Thread Tips
- Each tweet in the thread must respect Twitter's character limit (280 characters).
- Threads are scheduled as a single unit and posted all at once.
- Images can be attached to individual tweets via the field on each
assets.ThreadedPostInput
Mode: Create Image Post
Same as text post, but include an field with image URLs.
assetsbash
cat > /tmp/buffer_payload.json << 'EOF'
{"query": "mutation CreatePost($input: CreatePostInput!) { createPost(input: $input) { ... on PostActionSuccess { post { id text status dueAt } } ... on MutationError { message } } }", "variables": {"input": {"channelId": "<CHANNEL_ID>", "text": "<POST_CONTENT>", "schedulingType": "automatic", "mode": "addToQueue", "assets": {"images": [{"url": "<IMAGE_URL>"}]}}}}
EOF
curl -s -X POST https://api.buffer.com \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BUFFER_API_TOKEN" \
-H "User-Agent: Mozilla/5.0" \
-d @/tmp/buffer_payload.json | jq .Images must be publicly accessible URLs. Multiple images can be included in the array.
imagesMode: Create Idea
Save an idea for later use.
bash
cat > /tmp/buffer_payload.json << 'EOF'
{"query": "mutation CreateIdea($input: CreateIdeaInput!) { createIdea(input: $input) { ... on Idea { id content { title text services } } } }", "variables": {"input": {"organizationId": "<ORG_ID>", "content": {"title": "<IDEA_TITLE>", "text": "<IDEA_BODY>", "services": ["twitter", "linkedin"]}}}}
EOF
curl -s -X POST https://api.buffer.com \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BUFFER_API_TOKEN" \
-H "User-Agent: Mozilla/5.0" \
-d @/tmp/buffer_payload.json | jq .For field details (title, text, services, tags), refer to .
IdeaContentInputreferences/api-reference.mdNote: Tags require existing tag objects with and fields — fetch existing tags first before using.
idcolorMode: Get Account
Note: The full account query (,id,name,) fails with a standard API token scope. Use Get Organizations instead to confirm account identity.timezone
bash
curl -s -X POST https://api.buffer.com \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BUFFER_API_TOKEN" \
-H "User-Agent: Mozilla/5.0" \
-d '{"query": "{ account { organizations { id name ownerEmail } } }"}' | jq .Common Workflows
Schedule a Post
Multi-step workflow when the user wants to schedule a post:
- Get organizations → extract
organizationId - Get channels → show available channels, let user pick (or match by service name)
- Create post → use selected with the post content
channelId
If the user specifies a service (e.g., "post to Twitter"), match it against the channel's field.
serviceCheck the Queue
- Get organizations → extract
organizationId - Get posts with and
filter: { status: "scheduled" }sort: { field: "dueAt", direction: "asc" } - Display posts grouped by date with channel info
Brainstorm and Save Ideas
- Get organizations → extract
organizationId - Help the user draft idea content
- Create idea with title, text, tags, and target services
Schema Introspection
Before attempting a mutation or querying a field you're unsure about, introspect the schema first. Don't guess — the API surface is limited.
List all available mutations:
bash
curl -s -X POST https://api.buffer.com \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BUFFER_API_TOKEN" \
-H "User-Agent: Mozilla/5.0" \
-d '{"query": "{ __schema { mutationType { fields { name } } } }"}' | jq '[.data.__schema.mutationType.fields[].name]'List all available queries:
bash
curl -s -X POST https://api.buffer.com \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BUFFER_API_TOKEN" \
-H "User-Agent: Mozilla/5.0" \
-d '{"query": "{ __schema { queryType { fields { name } } } }"}' | jq '[.data.__schema.queryType.fields[].name]'Inspect fields on a specific type:
bash
curl -s -X POST https://api.buffer.com \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BUFFER_API_TOKEN" \
-H "User-Agent: Mozilla/5.0" \
-d '{"query": "{ __type(name: \"<TYPE_NAME>\") { fields { name type { name kind } } } }"}' | jq '.data.__type.fields[]'Error Handling
GraphQL Errors
Check for the top-level array in every response:
errorsbash
result=$(curl -s -X POST https://api.buffer.com ...)
errors=$(echo "$result" | jq -r '.errors // empty')
if [ -n "$errors" ]; then
echo "GraphQL Error:"
echo "$result" | jq '.errors[].message'
exit 1
fiMutation Errors
Mutations return union types. Always handle the variant:
MutationErrorjson
{
"data": {
"createPost": {
"message": "Validation failed: text is required"
}
}
}Common Issues
- 403 Forbidden (error code 1010): Cloudflare is blocking the request. Always include in every curl call.
-H "User-Agent: Mozilla/5.0" - 401 Unauthorized: Token is invalid or expired. Regenerate at https://publish.buffer.com/settings/api
- Missing organizationId: Most queries require an org ID. Fetch organizations first.
- Invalid channelId: Verify the channel exists and belongs to the current organization.
- Past dueAt: When using , the
customSchedulemust be in the future.dueAt