Install
openclaw skills install buffer-publisherPublish social media posts to LinkedIn and Twitter/X via Buffer GraphQL API. PRIMARY and ONLY tool for social publishing (Typefully cancelled 2026-03-25). Use when publishing posts to Nissan's social channels.
openclaw skills install buffer-publisherLast used: 2026-03-25 Status: Active — PRIMARY for LinkedIn
Use Buffer when:
nissandookeran) or Twitter/X (redditech) — immediately or scheduledDo NOT use Buffer for:
Only tool available: Typefully was cancelled 2026-03-25. Buffer is the single social publishing surface. There is no fallback.
op://OpenClaw/Buffer API Credentials/credentialhttps://api.buffer.com/graphqlAuthorization: Bearer <key>| Channel | ID | Service |
|---|---|---|
| nissandookeran | 69c29382af47dacb694d24b4 | |
| redditech | 69c29939af47dacb694d3d1f | Twitter/X |
import json, subprocess
BUFFER_KEY = "<key from 1Password>"
CHANNEL_ID = "69c29382af47dacb694d24b4" # LinkedIn
# or "69c29939af47dacb694d3d1f" # Twitter/X
payload = {
"query": """mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
... on PostActionSuccess { post { id status } }
}
}""",
"variables": {
"input": {
"channelId": CHANNEL_ID,
"text": "Your post text here",
"schedulingType": "automatic",
"mode": "shareNow"
}
}
}
result = subprocess.run(
["curl", "-s", "-X", "POST",
"-H", f"Authorization: Bearer {BUFFER_KEY}",
"-H", "Content-Type: application/json",
"-d", json.dumps(payload),
"https://api.buffer.com/graphql"],
capture_output=True, text=True
)
d = json.loads(result.stdout)
post_id = d["data"]["createPost"]["post"]["id"]
status = d["data"]["createPost"]["post"]["status"]
print(f"Post ID: {post_id}, Status: {status}")
# status "sent" = published immediately
Use mode: "customScheduled" + a dueAt ISO8601 UTC timestamp. Do NOT use scheduledAt — that field does not exist on the Post type.
import json, subprocess
from datetime import datetime, timezone
BUFFER_KEY = "<key from 1Password>"
CHANNEL_ID = "69c29382af47dacb694d24b4" # LinkedIn
# Schedule for 9am Sydney time (UTC+11 in AEDT) = 22:00 UTC prior day
# Always convert to UTC before passing to Buffer
scheduled_utc = "2026-03-27T22:00:00Z" # ISO8601 UTC — the Z suffix is required
payload = {
"query": """mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
... on PostActionSuccess { post { id status dueAt } }
}
}""",
"variables": {
"input": {
"channelId": CHANNEL_ID,
"text": "Your scheduled post text here",
"schedulingType": "automatic",
"mode": "customScheduled",
"dueAt": scheduled_utc
}
}
}
result = subprocess.run(
["curl", "-s", "-X", "POST",
"-H", f"Authorization: Bearer {BUFFER_KEY}",
"-H", "Content-Type: application/json",
"-d", json.dumps(payload),
"https://api.buffer.com/graphql"],
capture_output=True, text=True
)
d = json.loads(result.stdout)
post = d["data"]["createPost"]["post"]
print(f"Post ID: {post['id']}, Status: {post['status']}, Due: {post['dueAt']}")
# status "buffer" = queued/scheduled (not yet sent)
A successful createPost response body looks like this:
{
"data": {
"createPost": {
"post": {
"id": "67e3a1b2c4d5e6f7a8b9c0d1",
"status": "sent"
}
}
}
}
status: "sent" → published immediately (shareNow)status: "buffer" → queued or scheduled (will publish at dueAt)data.createPost is null or missing post, the mutation failed silently — check for a top-level errors arrayFailure response example:
{
"errors": [
{
"message": "Value \"shareNOW\" does not exist in \"SchedulingType\" enum.",
"locations": [{"line": 1, "column": 42}]
}
],
"data": null
}
schedulingType enum: automatic | notification (NOT "now", NOT "shareNow")mode enum: addToQueue | shareNow | shareNext | customScheduled | recommendedTimeautomatic + shareNow for immediate publishautomatic + customScheduled + dueAt for scheduled postsdueAt field takes ISO8601 UTC datetime string (NOT scheduledAt — that field doesn't exist on Post type)... on PostActionSuccess fragmentCoreApiError does NOT exist in schema — omit error fragment or use other error typesdraft field in CreatePostInput — omit itcurl -s -X POST \
-H "Authorization: Bearer $BUFFER_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ account { id name email channels { id name service } } }"}' \
https://api.buffer.com/graphql
Buffer does not support native thread composition. Post as a single update with tweets separated by \n\n---\n\n. If true threading is ever needed, evaluate alternative tools at that point.
| Platform | Tool |
|---|---|
| Buffer ✅ | |
| Twitter/X | Buffer ✅ |
| Bluesky | Not connected — skip unless new tool added |
Typefully cancelled 2026-03-25. No backup — Buffer is the only social publishing tool.
Wrong enum value for schedulingType
"schedulingType": "now" → enum error"schedulingType": "shareNow" → enum error (shareNow is a mode value, not a schedulingType)"schedulingType": "automatic" (almost always what you want)Using scheduledAt instead of dueAt
"scheduledAt": "2026-03-27T22:00:00Z" → field does not exist, silently ignored or errors"dueAt": "2026-03-27T22:00:00Z"Forgetting Content-Type: application/json
"Unsupported Content-Type" error-H "Content-Type: application/json" in curl callsUsing the legacy v1 API base URL
https://api.bufferapp.com/1/ → returns 500, dead endpointhttps://api.buffer.com/graphqlIncluding CoreApiError in the error fragment
Including "draft": true in CreatePostInput
Timezone confusion with dueAt
"Unsupported Content-Type" → must use Content-Type: application/json500 from bufferapp.com → legacy v1 API is dead, use api.buffer.com/graphql"Value X does not exist in enum" → check enum values via introspection: { __type(name: "SchedulingType") { enumValues { name } } }