skills/buffer/SKILL.md
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.
npx skillsauth add dgalarza/agent-skills bufferInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Requires a BUFFER_API_TOKEN environment variable. Generate one at:
https://publish.buffer.com/settings/api
Verify the token is set before making any API calls:
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
fi
https://api.buffer.comapplication/jsonAuthorization: Bearer $BUFFER_API_TOKENMozilla/5.0 — required to avoid Cloudflare 403 blocksAll API calls follow this pattern:
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 jq for readable output. Use jq -e to detect errors.
Important: For queries with GraphQL variables (e.g. $input), the shell may expand $input even inside single quotes. Use a temp file with -d @file to avoid this:
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 -d directly.
Parse the user's intent to determine which operation to perform:
| Intent | Mode | Example |
|--------|------|---------|
| List organizations | organizations | "Show my Buffer organizations" |
| List channels | channels | "What channels do I have?" |
| View posts | posts | "Show my scheduled posts" |
| Create a text post | create-post | "Schedule a tweet saying..." |
| Create a Twitter/X thread | create-thread | "Post a thread on X..." |
| Create an image post | create-post | "Post this image to Instagram" |
| Save an idea | create-idea | "Save an idea about..." |
| Account info | account | "Show my Buffer account" |
Most operations require an organizationId. If the user hasn't specified one, fetch organizations first. If only one org exists, use it automatically.
Fetch the user's organizations. This is typically the first call needed.
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 organizationId from the response for subsequent calls.
List channels (social media accounts) for an organization.
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.
Query posts with filtering, sorting, and pagination.
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.md.
Create and schedule a text post.
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 .
automatic (Buffer picks time) or notification (sends reminder)addToQueue, shareNow, shareNext, customSchedule, recommendedTime)customSchedule. Example: "2026-03-15T14:00:00Z"For full field definitions and enum values, refer to references/api-reference.md.
The mutation returns a union type. Always check for both success and error:
# 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'
}
Twitter/X threads are created using the metadata.twitter.thread field on the createPost mutation. The thread is an array of ThreadedPostInput objects, each with a text field (and optional assets).
Important: The first tweet in the thread must be included in the thread array. The top-level text 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.
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 .
text: Required. Use the first tweet's text.metadata.twitter.thread: Array of ThreadedPostInput objects. Each has:
text (String): The tweet contentassets (AssetsInput, optional): Images for that specific tweetthread array should match the top-level text (this is what Buffer displays as tweet 1).assets field on each ThreadedPostInput.Same as text post, but include an assets field with image URLs.
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 images array.
Save an idea for later use.
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 IdeaContentInput field details (title, text, services, tags), refer to references/api-reference.md.
Note: Tags require existing tag objects with id and color fields — fetch existing tags first before using.
Note: The full account query (
id,name,timezone) fails with a standard API token scope. Use Get Organizations instead to confirm account identity.
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 .
Multi-step workflow when the user wants to schedule a post:
organizationIdchannelId with the post contentIf the user specifies a service (e.g., "post to Twitter"), match it against the channel's service field.
organizationIdfilter: { status: "scheduled" } and sort: { field: "dueAt", direction: "asc" }organizationIdBefore 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:
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:
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:
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[]'
Check for the top-level errors array in every response:
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
fi
Mutations return union types. Always handle the MutationError variant:
{
"data": {
"createPost": {
"message": "Validation failed: text is required"
}
}
}
-H "User-Agent: Mozilla/5.0" in every curl call.customSchedule, the dueAt must be in the future.development
Use this skill when writing, rewriting, or reviewing feedback comments so they follow the Conventional Comments format.
development
Interact with the CreatorSignal API: submit video ideas for AI validation, poll for scored Go/Refine/Kill verdicts, manage channels and webhooks, and check quota. Use this skill whenever the user mentions CreatorSignal API, video idea validation, cs_live_ tokens, validation polling, webhook endpoints, or programmatic idea submission.
tools
Interact with the Buttondown newsletter API to manage tags, automations, subscribers, and emails. Use this skill whenever the user mentions Buttondown, newsletter tags, newsletter automations, email subscribers, or wants to manage any aspect of their Buttondown newsletter -- even if they just say 'my newsletter' without explicitly naming Buttondown.
development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.