Post sets

Create, schedule, list, and update Pallyy post sets via the API: one scheduled slot holding a post for each social network it targets.

A post set is one slot on your schedule: a date, a status, and one post per social network it targets. Scheduling the same content to Instagram and X is one post set with two posts, each carrying its own caption, media, and network-specific fields.

A post set moves through four statuses:

StatusMeaning
DRAFTParked, will not publish until scheduled
SCHEDULEDWill publish at scheduledAt
PUBLISHINGPublishing right now, read-only
PUBLISHEDDone, read-only. Each post carries a result

Creating or updating a set as DRAFT needs the post-sets:write scope. Anything that leaves a set SCHEDULED additionally needs post-sets:publish, see authentication.

List post sets

GET /v1/post-sets
ParameterRequiredMeaning
socialSetIdYesThe social set to list
page, sizeNoSee pagination
filters[startDate]NoISO 8601, sets scheduled at or after this time
filters[endDate]NoISO 8601, sets scheduled before this time
filters[status][]NoOne or more of DRAFT, SCHEDULED, PUBLISHING, PUBLISHED
filters[socialNetworks][]NoOnly sets containing posts for these networks, one or more of INSTAGRAM, FACEBOOK, TWITTER, LINKEDIN, GMB, PINTEREST, TIKTOK, YOUTUBE, THREADS, BLUESKY
filters[approval][]NoOne or more of NONE, PENDING, EXTERNAL_PENDING, APPROVED, DENIED
filters[labelsId][]NoOnly sets carrying these label ids
filters[search]NoCaption text search, at least 3 characters
sort[scheduledAt], sort[createdAt]NoASC or DESC
curl "https://app.pallyy.com/api/v1/post-sets?socialSetId=SET_ID&filters[status][]=SCHEDULED&sort[scheduledAt]=ASC" \
  -H "Authorization: Bearer pallyy_your_api_key"

Get a post set

GET /v1/post-sets/{id}

Returns the full post set, or a 404 if it does not exist or is outside the key's access.

Create a post set

POST /v1/post-sets

Requires post-sets:write, plus post-sets:publish when status is SCHEDULED. Returns the created set with a 201.

FieldRequiredMeaning
socialSetIdYesThe social set to create in
scheduledAtYesISO 8601 date-time the set publishes at
statusYesDRAFT or SCHEDULED
postsYes1 to 11 post objects, one per targeted network
repeatNo{ "interval": "DAY" | "WEEK" | "MONTH" | "YEAR", "occurrences": 2-50 }

Post sets created via the API never require approval, carry no labels, and are never locked.

Repeats

The repeat option turns one request into a repeating series. The first occurrence publishes at scheduledAt, and each following occurrence is spaced one interval apart (DAY, WEEK, MONTH, or YEAR), for a total of occurrences post sets, between 2 and 50. The series is materialized immediately: one post set per occurrence, all sharing the same seriesId, and every occurrence counts against your plan's monthly post limit.

Once a set belongs to a series, its repeat rule can no longer be changed via the API, matching the in-app editor: updating it returns a 400 with post-set:repeat_not_updatable. You can still edit each occurrence individually, since each one is a regular post set. Repeats are only available on plans that include them, otherwise the request fails with post-set:repeats_not_available.

Post objects

Every post shares these fields:

FieldRequiredMeaning
accountTypeYesThe network to publish to, see the account type values on social sets
captionYesThe caption text. Each network's own length limit applies
mediaYesMedia items, may be empty where the network allows text-only posts

Media items reference your media library by id, with optional per-item metadata:

{
  "mediaLibraryId": "665f1c2ab7e2a4d1f0a1b2c5",
  "altText": "A latte on a wooden table"
}

Besides altText, items accept title, description, link, tags, and products where the network supports them. The referenced media must belong to the same social set as the post set. To get media into the library via the API, see media uploads.

Network-specific fields

NetworkFields
FACEBOOKtype (required): TEXT, IMAGE, VIDEO, CAROUSEL, MULTI_IMAGE, REEL, or STORY. richCaption (required, see below). Optional location (see below), videoCoverImageSeconds
INSTAGRAMtype (required): IMAGE, CAROUSEL, REEL, or STORY. collaborators (required, pass [] for none). Optional location (see below), firstComment, audio, audioName, videoCoverImage (seconds into the first video)
LINKEDIN_PAGE, LINKEDIN_PERSONALrichCaption (required, see below)
GMBctaType (required): NONE, SIGN_UP, CALL, SHOP, LEARN_MORE, ORDER, or BOOK. Optional ctaUrl
PINTERESTtitle (required), website (required), optional board as { "id", "name" }
YOUTUBEtitle (required), privacy (required): PUBLIC, PRIVATE, or UNLISTED
TWITTER, TIKTOK, THREADS, BLUESKYCaption and media only

Rich captions and mentions

richCaption on Facebook and LinkedIn is the caption split into 1 to 32 segments, a mix of plain strings and mention objects, so pages and profiles can be tagged inline. Without mentions, pass the caption as a single-item array: ["Your caption"].

[
  "Grabbing a coffee with ",
  { "mention": { "id": "106039436102339", "index": "0", "value": "Pallyy", "denotationChar": "@" } },
  " this morning."
]

Each mention object wraps its fields under a mention key:

FieldMeaning
idThe platform's id for the tagged page or profile
indexZero-based position of the mention among the caption's mentions, as a numeric string
valueThe display text, without the denotation character
denotationCharThe character prefixing the mention, usually @

The location object

Facebook and Instagram posts can tag a place by passing location:

{
  "id": "108424279189115",
  "name": "New York, New York",
  "location": {
    "city": "New York",
    "country": "United States",
    "state": "NY",
    "zip": "10001"
  }
}
FieldRequiredMeaning
idYesThe Facebook place id
nameYesThe place's display name
locationYesThe place's address, all fields optional: city, country, state, zip

Place ids come from Facebook's places database, the same one Pallyy's composer searches when you tag a location.

Example

curl https://app.pallyy.com/api/v1/post-sets \
  -X POST \
  -H "Authorization: Bearer pallyy_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "socialSetId": "665f1c2ab7e2a4d1f0a1b2c3",
    "scheduledAt": "2026-09-01T09:30:00.000Z",
    "status": "SCHEDULED",
    "posts": [
      {
        "accountType": "INSTAGRAM",
        "type": "IMAGE",
        "caption": "Fresh from the roastery.",
        "collaborators": [],
        "media": [{ "mediaLibraryId": "665f1c2ab7e2a4d1f0a1b2c5", "altText": "A latte on a wooden table" }]
      },
      {
        "accountType": "TWITTER",
        "caption": "Fresh from the roastery.",
        "media": [{ "mediaLibraryId": "665f1c2ab7e2a4d1f0a1b2c5" }]
      }
    ]
  }'

Validation and plan limits

Drafts are validated loosely, so you can park incomplete content. Scheduling validates every post against its network's rules, and failures return post-set:invalid_posts with one entry per problem, see errors.

Your plan is enforced on every write: the monthly post limit (post-set:monthly_posts_exceeded), carousels (post-set:carousels_not_available), videos (post-set:videos_not_available), and repeats (post-set:repeats_not_available) all return a 403 when unavailable.

Update a post set

PATCH /v1/post-sets/{id}

Requires post-sets:write, plus post-sets:publish when the set ends up SCHEDULED, whether because you set the status or because it already was. The update is partial: omitted fields keep their saved values.

FieldMeaning
scheduledAtNew publish time
statusDRAFT or SCHEDULED
repeatTurn the set into a repeating series. Not allowed on a set that already belongs to one
postsReplaces the set's posts entirely, see below

When posts is provided, it describes the complete new list:

  • A post with an id keeps that existing post's identity. Its accountType cannot change.
  • A post without an id is created new.
  • Existing posts that are not referenced are removed.
  • Each post's media works the same way: { "id": "..." } keeps an existing media item of the set (it may move between posts), { "mediaLibraryId": "..." } adds a new one from the library, and unreferenced media are removed.
  • Each post or media id may be referenced at most once, otherwise the request fails with post-set:duplicate_references.

Sets that are PUBLISHING or PUBLISHED are read-only and return a 412 with post-set:read_only.

The post set object

FieldTypeMeaning
idstringThe post set id
socialSetIdstringThe social set it belongs to
scheduledAtstringISO 8601 publish time
statusstringDRAFT, SCHEDULED, PUBLISHING, or PUBLISHED
postsarrayThe per-network posts, including their media and network-specific fields
seriesIdstringPresent when the set belongs to a repeating series
repeatobjectThe repeat rule, when the set started a series
labelsIdarrayLabel ids applied in Pallyy
approvalstringThe approval state within Pallyy's approval workflow
isLockedbooleanWhether the set is locked in Pallyy
createdAt, updatedAtstringISO 8601 timestamps

Once a set has published, each post carries a result:

{
  "result": {
    "status": "POSTED",
    "providerId": "18123456789",
    "permalink": "https://www.instagram.com/p/..."
  }
}

Failed posts have "status": "FAILED" with an optional message and one of these reason codes:

ReasonMeaning
ACCOUNT_CONNECTION_EXPIREDThe account's connection expired and needs to be reauthorized in Pallyy
ACCOUNT_RESTRICTEDThe network has restricted the account
ACCOUNT_RESTRICTED_SPAMThe network has restricted the account for spam
ACCOUNT_SUSPENDEDThe network has suspended the account
ACTION_BLOCKEDThe network blocked the publishing action
CAPTION_TOO_LONGThe caption exceeds the network's length limit
UNKNOWN_MEDIA_ERRORThe network rejected the post's media
UNKNOWNThe publish failed for another reason, check message
View as markdown

More in Endpoints

Questions about the API? Email us at hey@pallyy.com and we'll get back to you.