Notes
Use Notes to add feedback, review comments, or internal context to a post or channel-less draft in Buffer. You can list, create, update, and delete Notes. These operations are experimental.
Before you start
You need a Buffer account, a personal API key or OAuth access token, and access to the post or channel-less draft you want to work with. For an app used by other people, use OAuth so each person connects their own Buffer account.
Request notes:read to list Notes and notes:write to create, update, or delete them. Request both for the complete workflow. These permissions do not replace the connected person's organization, channel, or role permissions.
Existing tokens do not gain Notes access automatically. Create a new personal key, or update your app client's permitted scopes and ask the person to authorize again with the Notes scopes. Other operations, such as finding posts or content items, require their own scopes.
Choose a thread
A Note belongs to exactly one subject. Use one of these objects:
{ "postId": "YOUR_POST_ID" }
{ "contentItemId": "YOUR_CONTENT_ITEM_ID" }
Use contentItemId for a channel-less draft's own thread. This is a ContentItem ID, not an Idea-board ID. A ContentItem's thread is separate from the threads on its channel-specific Posts. Provide exactly one subject field, with a non-null value. After a channel-less draft becomes channel-specific Posts, its original thread is closed to new Notes; use a Post's thread for new feedback.
1. List Notes
Run this query with the variables below:
query ListNotes($input: CollaborationNotesInput!, $first: Int = 10, $after: String) {
collaborationNotes(input: $input, first: $first, after: $after) {
edges {
cursor
node {
id
text
annotations { type text content indices url displayValue serviceEntityId }
authorId
author { id name }
allowedActions
createdAt
updatedAt
}
}
pageInfo { hasNextPage endCursor }
}
}
{
"input": { "subject": { "postId": "YOUR_POST_ID" } },
"first": 10,
"after": null
}
Notes are returned newest first. A page defaults to 10 Notes and accepts 1–100. When pageInfo.hasNextPage is true, pass pageInfo.endCursor as after to fetch the next page. Treat cursors as opaque strings.
The author can be null if their account was deleted. authorId remains available. Only request profile fields your app needs; the examples use ID and name.
2. Create a Note
Run this mutation with the variables below:
mutation CreateNote($input: CreateCollaborationNoteInput!) {
createCollaborationNote(input: $input) {
__typename
... on CreateCollaborationNoteSuccess {
edge { cursor node { id text allowedActions } }
}
... on MutationError { message }
}
}
{
"input": {
"subject": { "postId": "YOUR_POST_ID" },
"text": "Please review the revised caption.",
"annotations": []
}
}
A successful response has __typename: CreateCollaborationNoteSuccess. Save edge.node.id for later edits or deletion. Creating a Note does not publish the post.
For a channel-less draft, replace the subject with { "contentItemId": "YOUR_CONTENT_ITEM_ID" }. The rest of the request stays the same.
3. Update a Note
Run this mutation with the variables below:
mutation UpdateNote($input: UpdateCollaborationNoteInput!) {
updateCollaborationNote(input: $input) {
__typename
... on UpdateCollaborationNoteSuccess { note { id text allowedActions } }
... on MutationError { message }
}
}
{
"input": {
"noteId": "YOUR_NOTE_ID",
"text": "The revised caption is ready for review.",
"annotations": []
}
}
An update replaces the Note's text and annotations. Omitting annotations, passing null, or passing an empty array clears existing annotations. When editing formatted content, send annotations that match the replacement text; copying old character positions after changing text can make them invalid.
Use updateNote and deleteNote in the Note's allowedActions response to decide whether to show edit or delete controls. The API checks permissions again when the request runs.
4. Delete a Note
Run this mutation with the variables below:
mutation DeleteNote($input: DeleteCollaborationNoteInput!) {
deleteCollaborationNote(input: $input) {
__typename
... on DeleteCollaborationNoteSuccess { noteId }
... on MutationError { message }
}
}
{ "input": { "noteId": "YOUR_NOTE_ID" } }
Ask the person to confirm before deleting. Deletion is permanent. A successful response has __typename: DeleteCollaborationNoteSuccess and the deleted noteId. Listing the thread again should no longer return that Note.
Handle errors
Check both top-level GraphQL errors and the mutation result's __typename. HTTP 200 alone does not mean the mutation succeeded.
- Missing token permissions can return
INSUFFICIENT_SCOPEin top-levelerrors. Request the required scope and authorize again; retrying with the same token will not add access. - A mutation can return a typed error instead of its success type. The examples select
messagethroughMutationError. Creation can returnInvalidInputError,LimitReachedError, orCollaborationNoteThreadClosedError; update can returnInvalidInputError. - A closed thread accepts no new Notes, but existing Notes remain readable.
- Respect API rate limits and the
Retry-Afterheader. Do not blindly retry a create request after a network timeout: it may already have saved the Note.
Notifications
Notes created through the API use Buffer's existing batched notification flow. Eligible activity is grouped by recipient and organization in 30-minute windows. Delivery depends on notification preferences, access, read state, and other eligibility checks. A successful create response is not confirmation that an email was sent.