Your First Post
Let's walk through creating your first post with the Buffer API. By the end, you'll have a post scheduled in your queue.
Prerequisites: A Buffer account with at least one connected channel, and an API key. See Authentication if you don't have a key yet.
Time: ~5 minutes
Step 1: Get your organization ID
First, query your account to find your organization ID:
query GetOrganizations {
account {
organizations {
id
name
}
}
}
curl -X POST 'https://api.buffer.com' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-d '{"query": "query GetOrganizations {\n account {\n organizations {\n id\n name\n }\n }\n}"}'
const response = await fetch('https://api.buffer.com', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY',
},
body: JSON.stringify({
query: `
query GetOrganizations {
account {
organizations {
id
name
}
}
}
`,
}),
});
const data = await response.json();
console.log(data);
<?php
$query = '
query GetOrganizations {
account {
organizations {
id
name
}
}
}
';
$payload = [
'query' => $query,
];
$ch = curl_init('https://api.buffer.com');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer YOUR_API_KEY',
],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
print_r($data);
You'll get a response like this:
{
"data": {
"account": {
"organizations": [
{ "id": "your_org_id", "name": "My Company" }
]
}
}
}
Copy the id from the response. You'll need it in the next step.
Step 2: Get your channel ID
Now query your channels using the organization ID from Step 1:
query GetChannels {
channels(input: { organizationId: "your_org_id" }) {
id
name
service
}
}
curl -X POST 'https://api.buffer.com' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-d '{"query": "query GetChannels {\n channels(input: { organizationId: \"your_org_id\" }) {\n id\n name\n service\n }\n}"}'
const response = await fetch('https://api.buffer.com', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY',
},
body: JSON.stringify({
query: `
query GetChannels {
channels(input: { organizationId: "your_org_id" }) {
id
name
service
}
}
`,
}),
});
const data = await response.json();
console.log(data);
<?php
$query = '
query GetChannels {
channels(input: { organizationId: "your_org_id" }) {
id
name
service
}
}
';
$payload = [
'query' => $query,
];
$ch = curl_init('https://api.buffer.com');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer YOUR_API_KEY',
],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
print_r($data);
This returns all your connected social profiles:
{
"data": {
"channels": [
{ "id": "your_channel_id", "name": "My Twitter", "service": "twitter" },
{ "id": "your_other_channel_id", "name": "My Instagram", "service": "instagram" }
]
}
}
Pick the channel you want to post to and copy its id.
Step 3: Create your post
Now create a post using the channel ID from Step 2:
mutation CreateFirstPost {
createPost(input: {
text: "Hello from the Buffer API!",
channelId: "your_channel_id",
schedulingType: automatic,
mode: addToQueue
}) {
... on PostActionSuccess {
post {
id
text
dueAt
}
}
... on MutationError {
message
}
}
}
curl -X POST 'https://api.buffer.com' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-d '{"query": "mutation CreateFirstPost {\n createPost(input: {\n text: \"Hello from the Buffer API!\",\n channelId: \"your_channel_id\",\n schedulingType: automatic,\n mode: addToQueue\n }) {\n ... on PostActionSuccess {\n post {\n id\n text\n dueAt\n }\n }\n ... on MutationError {\n message\n }\n }\n}"}'
const response = await fetch('https://api.buffer.com', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY',
},
body: JSON.stringify({
query: `
mutation CreateFirstPost {
createPost(input: {
text: "Hello from the Buffer API!",
channelId: "your_channel_id",
schedulingType: automatic,
mode: addToQueue
}) {
... on PostActionSuccess {
post {
id
text
dueAt
}
}
... on MutationError {
message
}
}
}
`,
}),
});
const data = await response.json();
console.log(data);
<?php
$query = '
mutation CreateFirstPost {
createPost(input: {
text: "Hello from the Buffer API!",
channelId: "your_channel_id",
schedulingType: automatic,
mode: addToQueue
}) {
... on PostActionSuccess {
post {
id
text
dueAt
}
}
... on MutationError {
message
}
}
}
';
$payload = [
'query' => $query,
];
$ch = curl_init('https://api.buffer.com');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer YOUR_API_KEY',
],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
print_r($data);
A successful response looks like this:
{
"data": {
"createPost": {
"post": {
"id": "your_post_id",
"text": "Hello from the Buffer API!",
"dueAt": "2026-03-05T14:30:00.000Z"
}
}
}
}
Step 4: Verify in Buffer
Open your Buffer dashboard. You should see your new post in the queue for the channel you selected. With mode: addToQueue, we've assigned it to the next available time slot.
Scheduling options
The example above used mode: addToQueue, which adds the post to the next available time slot. You can also schedule a post for a specific time:
mutation CreateScheduledPost {
createPost(input: {
text: "Scheduled for a specific time",
channelId: "your_channel_id",
schedulingType: automatic,
mode: customScheduled,
dueAt: "2026-03-10T15:00:00.000Z"
}) {
... on PostActionSuccess {
post {
id
text
dueAt
}
}
... on MutationError {
message
}
}
}
curl -X POST 'https://api.buffer.com' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-d '{"query": "mutation CreateScheduledPost {\n createPost(input: {\n text: \"Scheduled for a specific time\",\n channelId: \"your_channel_id\",\n schedulingType: automatic,\n mode: customScheduled,\n dueAt: \"2026-03-10T15:00:00.000Z\"\n }) {\n ... on PostActionSuccess {\n post {\n id\n text\n dueAt\n }\n }\n ... on MutationError {\n message\n }\n }\n}"}'
const response = await fetch('https://api.buffer.com', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY',
},
body: JSON.stringify({
query: `
mutation CreateScheduledPost {
createPost(input: {
text: "Scheduled for a specific time",
channelId: "your_channel_id",
schedulingType: automatic,
mode: customScheduled,
dueAt: "2026-03-10T15:00:00.000Z"
}) {
... on PostActionSuccess {
post {
id
text
dueAt
}
}
... on MutationError {
message
}
}
}
`,
}),
});
const data = await response.json();
console.log(data);
<?php
$query = '
mutation CreateScheduledPost {
createPost(input: {
text: "Scheduled for a specific time",
channelId: "your_channel_id",
schedulingType: automatic,
mode: customScheduled,
dueAt: "2026-03-10T15:00:00.000Z"
}) {
... on PostActionSuccess {
post {
id
text
dueAt
}
}
... on MutationError {
message
}
}
}
';
$payload = [
'query' => $query,
];
$ch = curl_init('https://api.buffer.com');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer YOUR_API_KEY',
],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
print_r($data);
The dueAt field accepts an ISO 8601 datetime string in UTC.
Handling errors
If something goes wrong, the response includes a MutationError with a message field instead of PostActionSuccess:
{
"data": {
"createPost": {
"message": "Channel not found"
}
}
}
Common issues:
- Invalid
channelId- double-check you copied the right ID from Step 2 - Missing required fields -
textandchannelIdare always required - Queue limit reached: your channel's queue is full
Always include ... on MutationError { message } in your mutations to catch errors. See Error Handling for more details.
Next steps
- Create posts with images: add images to your posts
- Posts & Scheduling: learn about scheduling types and post lifecycle
- Data Model: understand the full object hierarchy