Publishing

Queues and recycling

Give a profile recurring weekly posting slots, add posts to the next free slot with queuedFromProfile, and republish evergreen posts on a schedule.

A queue is a weekly timetable for a profile: Monday 09:00, Wednesday 09:00, Friday 17:30. Instead of picking a time for every post, you add posts to the queue and each one takes the next free slot. Fifty posts become fifty slots without a single scheduledFor.

Queues belong to profiles, not to accounts. A post added to a profile's queue publishes to whichever accounts you list in its platforms.

#Create a queue

POST /v1/queue/slots takes a profile, a name, a timezone and the weekly slots. dayOfWeek runs from 0 (Sunday) to 6 (Saturday) and time is HH:mm in 24-hour format, read in the queue's timezone.

curl -X POST https://api.pozy.ai/v1/queue/slots \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profileId": "670f9b1d4c2e8a7f3b6d5e10",
    "name": "Weekday mornings",
    "timezone": "Europe/London",
    "slots": [
      { "dayOfWeek": 1, "time": "08:45" },
      { "dayOfWeek": 3, "time": "08:45" },
      { "dayOfWeek": 5, "time": "12:30" }
    ]
  }'
Response (201)
{
  "success": true,
  "schedule": {
    "_id": "6722f1a93b0c4d5e6f7a8b90",
    "profileId": "670f9b1d4c2e8a7f3b6d5e10",
    "name": "Weekday mornings",
    "timezone": "Europe/London",
    "slots": [
      { "dayOfWeek": 1, "time": "08:45" },
      { "dayOfWeek": 3, "time": "08:45" },
      { "dayOfWeek": 5, "time": "12:30" }
    ],
    "active": true,
    "isDefault": true
  },
  "nextSlots": ["2026-11-02T08:45:00+00:00", "2026-11-04T08:45:00+00:00"]
}

The first queue a profile gets becomes its default. A profile can have several queues, for example one for product news and one for weekend content. Create another with the same profileId and a different name.

#Add a post to the queue

Create the post with queuedFromProfile set to the profile id and no scheduledFor. Pozy locks the next free slot for it, so the next post you add takes the slot after that.

curl -X POST https://api.pozy.ai/v1/posts \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Tip of the week: export any report as CSV from the share menu.",
    "platforms": [
      { "platform": "linkedin", "accountId": "6710c3e2a9f14b0d8e5c7a21" },
      { "platform": "twitter", "accountId": "6710c3e2a9f14b0d8e5c7a23" }
    ],
    "queuedFromProfile": "670f9b1d4c2e8a7f3b6d5e10"
  }'

The post comes back scheduled, with the slot's time in scheduledFor (UTC) and the queue in queueId. Add queueId next to queuedFromProfile to target a queue other than the default one.

Do not copy the next slot into scheduledFor

GET /v1/queue/next-slot is for showing people when a post would go out. If you read it and then send that time as scheduledFor, two posts created at the same moment can land on the same slot. Send queuedFromProfile and let Pozy assign the slot.

#Preview upcoming slots

Call Returns
GET /v1/queue/next-slot?profileId=... The next free slot, its timezone and the queue it belongs to. 404 when the profile has no queue or no free slot.
GET /v1/queue/preview?profileId=...&count=10 The next count slot times (up to 100) as ISO date-times.
GET /v1/queue/slots?profileId=... The default queue with its slots and next times. Add all=true for every queue of the profile, or queueId for one.

#Change or remove a queue

PUT /v1/queue/slots replaces a queue's slots, name, timezone or active state. Without queueId it changes the default queue; with queueId it changes that one.

Field What it does
slots, timezone Required. The full new timetable.
name Rename the queue.
active false pauses the queue. next-slot then returns 400 and new posts cannot join it.
setAsDefault true makes this queue the profile's default.
reshuffleExisting true moves posts already waiting in the queue onto the new timetable. The response reports reshuffledCount.

DELETE /v1/queue/slots?profileId=...&queueId=... deletes one queue. Leave out queueId to delete every queue of the profile. Deleting the default queue promotes another one to default.

#Common errors

Error Cause Fix
400 on create or update A slot with time not in HH:mm, a dayOfWeek outside 0 to 6, or an unknown timezone. Fix the slot or use a canonical IANA name.
404 on next-slot The profile has no queue, or every slot is taken. Create a queue or add slots.
409 queue_slot_conflict on PUT /v1/posts/{postId} You moved a queued post onto a time another post in the same queue already holds. Pick another time, drop scheduledFor, or send queueId: null to schedule it outside the queue.

#Recycle evergreen posts

Recycling republishes a post on a repeating schedule, which suits evergreen content such as guides, FAQs or a pinned offer. Set recycling when you create or update the post:

Request body (excerpt)
{
  "content": "New here? Our 5-minute setup guide covers everything.",
  "platforms": [{ "platform": "linkedin", "accountId": "6710c3e2a9f14b0d8e5c7a21" }],
  "scheduledFor": "2026-11-02T09:00:00",
  "timezone": "Europe/London",
  "recycling": {
    "enabled": true,
    "gap": 2,
    "gapFreq": "month",
    "expireCount": 6,
    "contentVariations": [
      "New here? Our 5-minute setup guide covers everything.",
      "Setting up a new workspace? Start with the 5-minute guide.",
      "The fastest way to get started is still the 5-minute setup guide."
    ]
  }
}
Field What it does
enabled Turns recycling on or off. Defaults to true when you send recycling.
gap and gapFreq How long to wait between copies: gap weeks or months (gapFreq is week or month, default month).
startDate When the first copy may go out.
expireCount Stop after this many copies. null for no limit.
expireDate Stop after this date. null for no limit.
contentVariations Texts to rotate through, so followers do not see the same words every time.

Each copy is a new post with its own id. It records the original in recycledFromPostId, fires post.recycled, then follows the normal lifecycle with its own post.scheduled and publish events. The original post shows progress in recycling.recycleCount, recycling.nextRecycleAt and recycling.lastRecycledAt.

Recycling is the one thing you can still change on a published post: send a new recycling object with PUT /v1/posts/{postId}, or "enabled": false to stop it.

#Endpoints

Endpoint What it does
GET /v1/queue/slots List schedules
POST /v1/queue/slots Create schedule
PUT /v1/queue/slots Update schedule
DELETE /v1/queue/slots Delete schedule
GET /v1/queue/preview Preview upcoming slots
GET /v1/queue/next-slot Get next available slot

#Webhook events

Event When it fires
post.scheduled Post scheduled.
post.recycled Post recycled.