Posts
A versioned API for posting content from an outside tool: n8n, Make, Zapier, or your own script. Create a post, optionally schedule it to connected channels, and check on it later.
All of it lives under /v1, for example https://api.postlyra.com/v1/posts.
This still lands in your review queue
Creating a post here never publishes it immediately. A scheduled publication only goes out through the normal queue, at its scheduled time, and only once the post is approved: by you in Studio, by the mobile app, or (only with approve: true below) by the call itself, recorded in your name. There is no way to publish the instant this call returns. See Approve and schedule.
GET /v1/posts
Keyset-listed (?before=&before_id=), newest first. Returns { "items": [...], "hasMore": false }.
POST /v1/posts
Creates a post, optionally scheduling it.
curl -X POST https://api.postlyra.com/v1/posts \
-H "Authorization: Bearer $POSTLYRA_TOKEN" \
-H "X-Postlyra-Brand: $BRAND_ID" \
-H "Content-Type: application/json" \
-d '{
"kind": "text",
"body": "The post text.",
"submit": true,
"publications": [
{ "account_id": 42, "scheduled_at": "2026-08-25T15:00:00Z" }
]
}'| Field | Meaning |
|---|---|
kind | text (default), reel, carousel or video. A format, not a network |
title | Optional working title |
body | The post text |
thread | Optional array of follow-up posts, for platforms that support threading |
content_profile_id | Optional identity for a carousel's slides. See Identities |
pillar | Optional content pillar key |
submit | true lands the post awaiting_approval instead of draft |
approve | true creates the post already approved, recorded as your account in approved_via: "api". Implies submit. Refused with 403 tier_denied on a token minted below elevated_write access; see Authentication |
publications | Optional list of {account_id, scheduled_at, caption, first_comment, compose_options} targets |
publications[].account_id comes from GET /v1/channels. Each target needs a different account and a future scheduled_at; send an explicit timezone offset, since a bare timestamp is read as UTC.
A connector preflight failure (a caption too long, a required image missing) refuses the whole call, nothing gets created:
{ "code": "preflight_failed", "issues": { "42": ["Caption exceeds 300 characters."] } }On success: 201 with { "post": { ... } }.
GET /v1/posts/{post}
The post plus its publications.
DELETE /v1/posts/{post}/publications/{publication}
Cancels a pending publication (marks it skipped; nothing is ever hard-deleted, so the history stays intact). 422 on one that already fired.
GET /v1/channels
The brand's connected, active channels and what each one accepts, the same data the composer uses:
{
"channels": [
{
"account_id": 42,
"platform": "linkedin",
"platform_label": "LinkedIn",
"handle": "@yourbrand",
"caption_limit": 3000,
"max_media_items": 9,
"supports_thread": false,
"supports_first_comment": true
}
],
"account_groups": [{ "id": 1, "name": "Founder", "account_ids": [42] }]
}GET /v1/slots/next?account_id=
The next free posting slot on that channel's own cadence, the same one Settings → Content configures. See Posting schedule.
Media
/v1/media/... is the same media library every other surface uses, mounted under /v1 too.