Layers

POST /v1/content/:containerId/schedule

Schedule a content container to one or more connected accounts at a specific time. The approval gate can block unapproved content.

View as Markdown
POST/v1/content/:containerId/schedule
Phase 1stableidempotent
Auth
Bearer
Scope
publish:write

Schedule a completed content container to publish to N social accounts at a specific time. Each target gets its own scheduledPostId you can later reschedule or cancel.

Nothing publishes until the container's approval flag is set. If the project has requires_approval: true and the container is still approvalStatus: "pending", this call returns 202 with gateStatus: "blocked_on_approval" and stashes the intent on the container — a subsequent approve promotes it into scheduled_posts automatically. If approvalStatus is rejected, the call returns 409 CONTENT_REJECTED. See Approval.

The container must be status: "completed" — you can't schedule something that's still generating.

Path
  • containerId
    stringrequired
    Completed content container id.
Headers
  • Idempotency-Key
    string (UUID)optional
    Same key + same body replays the cached response for 24 hours. Recommended.
Body
  • scheduledFor
    string (ISO-8601)required
    When to publish. Schedule at least 30 seconds in the future; past/near-now values are accepted but the dispatcher may publish immediately on the next tick.
  • targets
    Target[]required
    One entry per destination account. At least one required.
Target
  • socialAccountId
    stringrequired
    Account id from list-social-accounts.
  • mode
    stringrequired
    Publish mode. Not every mode is valid on every platform — see table below.
    One of: direct_publish, draft_to_device, reels, feed
  • scheduledPostId
    stringoptional
    Partner-created id for this post. Server generates one if omitted.
  • captionOverride
    stringoptional
    Replace the container's caption for this target only.
  • firstCommentOverride
    stringoptional
    Replace the container's first comment for this target only.

Valid mode per platform

PlatformModes
TikTokdirect_publish, draft_to_device
Instagramreels, feed, draft_to_device

draft_to_device sends the media to the logged-in mobile app as a draft — the end-customer finishes posting by hand. Useful when platform ToS prefers a human tap.

The schedule request currently accepts any mode string per the enum; platform compatibility is enforced at publish time, not at schedule time. Sending a platform-incompatible mode will queue the post but fail during publish with a platform error. Strict schedule-time validation is planned.

Example request

curl https://api.layers.com/v1/content/cnt_01HXZM3K4N5P6QRS7TUV8WXYZ9/schedule \
  -H "Authorization: Bearer lp_live_01HX9Y6K7EJ4T2_4QZpN..." \
  -H "Idempotency-Key: 8f1d6c3e-4b2a-4a18-9e4f-c2d7a1b0e999" \
  -H "Content-Type: application/json" \
  -d '{
    "scheduledFor": "2026-04-19T14:00:00Z",
    "targets": [
      { "socialAccountId": "sa_01HXZ9P2M4N5KLM6TUV7WXYZ9A", "mode": "direct_publish" },
      { "socialAccountId": "sa_01HXZQ8N3C5R6STUV7WXYZ9AB", "mode": "reels", "captionOverride": "Fresh pour, ready in 30s." }
    ]
  }'
const result = await layers.publishing.schedule(
  {
    containerId: "cnt_01HXZM3K4N5P6QRS7TUV8WXYZ9",
    scheduledFor: "2026-04-19T14:00:00Z",
    targets: [
      { socialAccountId: "sa_01HXZ9P2M4N5KLM6TUV7WXYZ9A", mode: "direct_publish" },
      {
        socialAccountId: "sa_01HXZQ8N3C5R6STUV7WXYZ9AB",
        mode: "reels",
        captionOverride: "Fresh pour, ready in 30s.",
      },
    ],
  },
  { idempotencyKey: crypto.randomUUID() },
);

if (result.gateStatus === "blocked_on_approval") {
  // Approve the container or leave the posts queued; they flip to queued once approved.
}
result = layers.publishing.schedule(
    container_id="cnt_01HXZM3K4N5P6QRS7TUV8WXYZ9",
    scheduled_for="2026-04-19T14:00:00Z",
    targets=[
        {"socialAccountId": "sa_01HXZ9P2M4N5KLM6TUV7WXYZ9A", "mode": "direct_publish"},
        {"socialAccountId": "sa_01HXZQ8N3C5R6STUV7WXYZ9AB", "mode": "reels",
         "captionOverride": "Fresh pour, ready in 30s."},
    ],
    idempotency_key=str(uuid.uuid4()),
)

Response

200Scheduled
{
  "scheduledPostIds": [
    "sp_01HXZN4K5M6P7QRS8TUV9WXYZA",
    "sp_01HXZN4K5M6P7QRS8TUV9WXYZB"
  ],
  "gateStatus": "queued",
  "scheduledFor": "2026-04-19T14:00:00Z"
}
202Gated on approval — intent stashed on the container, will flip to queued on approval
{
  "scheduledPostIds": [
    "sp_01HXZN4K5M6P7QRS8TUV9WXYZA",
    "sp_01HXZN4K5M6P7QRS8TUV9WXYZB"
  ],
  "gateStatus": "blocked_on_approval",
  "scheduledFor": "2026-04-19T14:00:00Z"
}

gateStatus: "queued" (200) means scheduled_posts rows exist now and will attempt to publish at scheduledFor. gateStatus: "blocked_on_approval" (202) means the request was accepted but the rows do not yet exist — the intent is stashed on the container's pendingSchedule metadata; a subsequent approve call promotes those intents into live scheduled_posts rows. The scheduledPostIds are the stable ids those rows will adopt on promotion, so it's safe to record them on your side immediately.

Errors

StatusCodeWhen
422VALIDATIONEmpty targets, malformed scheduledFor, or bad enum value.
401UNAUTHENTICATEDMissing or invalid key.
403FORBIDDEN_SCOPEKey lacks publish:write.
404NOT_FOUNDContainer or a target account not in your organization.
409CONFLICTContainer not completed, or a scheduledPostId you created already exists with a different body.
409CONTENT_REJECTEDContainer's approval_status is rejected. Regenerate or replace the container.
429RATE_LIMITEDWrite budget exhausted.

See also

On this page