> ## Documentation Index
> Fetch the complete documentation index at: https://docs.postbreeze.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a post

> Creates a new post — either a draft you'll schedule later or one that's already scheduled to go out at a specific time — and queues it up for every account you list.

Send `content` (the caption shared across every platform) and a `platforms` array of one entry per account you want to post to. Each entry can override the caption or attach platform-specific settings via `platformOptions`.

If you include `scheduledFor`, the post is created as scheduled and Postbreeze queues it up to publish at that time. Leave it out and the post is saved as a draft instead.

Postbreeze figures out which workspace the post belongs to from the first account you list, so you don't need to pass a `workspaceId`.

Only workspace **owners**, **admins**, and **editors** can create posts.



## OpenAPI

````yaml /openapi.json post /posts
openapi: 3.0.0
info:
  title: Postbreeze API
  description: >-
    Public REST API for scheduling and managing social posts. Authenticate every
    request with `Authorization: Bearer pb_live_…`. All endpoints are scoped to
    a single workspace; an API key issued for workspace A cannot access
    workspace B.
  version: 1.0.0
  contact: {}
servers:
  - url: http://localhost:4100/api/v1
security:
  - bearer: []
tags: []
paths:
  /posts:
    post:
      tags:
        - Posts
      summary: Create a post
      description: >-
        Creates a new post — either a draft you'll schedule later or one that's
        already scheduled to go out at a specific time — and queues it up for
        every account you list.


        Send `content` (the caption shared across every platform) and a
        `platforms` array of one entry per account you want to post to. Each
        entry can override the caption or attach platform-specific settings via
        `platformOptions`.


        If you include `scheduledFor`, the post is created as scheduled and
        Postbreeze queues it up to publish at that time. Leave it out and the
        post is saved as a draft instead.


        Postbreeze figures out which workspace the post belongs to from the
        first account you list, so you don't need to pass a `workspaceId`.


        Only workspace **owners**, **admins**, and **editors** can create posts.
      operationId: PostsV1Controller_create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePostFlatDto'
      responses:
        '201':
          description: The newly created post.
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    description: Prefixed cuid identifier.
                  workspaceId:
                    type: string
                    description: Workspace this post belongs to.
                  createdByUserId:
                    type: string
                    description: User id of the author.
                  status:
                    type: string
                    enum:
                      - DRAFT
                      - NEEDS_APPROVAL
                      - SCHEDULED
                      - PUBLISHING
                      - PARTIALLY_PUBLISHED
                      - PUBLISHED
                      - FAILED
                      - CANCELED
                    description: >-
                      Aggregate publish state. Derived from per-target statuses
                      (`PARTIALLY_PUBLISHED` when some succeed and some fail).
                  caption:
                    type: string
                    nullable: true
                    description: >-
                      Default caption applied to every target unless overridden
                      via `targets[].captionOverride`.
                  scheduledAt:
                    type: string
                    format: date-time
                    nullable: true
                    description: >-
                      ISO-8601 publish time. Doubles as the calendar pin for
                      drafts (set via `draftScheduledAt`).
                  timezone:
                    type: string
                    nullable: true
                    description: >-
                      IANA timezone the post was composed in. Cosmetic — used by
                      the UI.
                  workflowId:
                    type: string
                    nullable: true
                    description: >-
                      Temporal workflow id driving this post's publish, when
                      scheduled. Null on drafts and after cancellation.
                  pendingWorkflowId:
                    type: string
                    nullable: true
                    description: >-
                      Workflow id staged during the schedule transaction.
                      Visible while a Temporal start is in flight; cleared on
                      commit.
                  approvedByUserId:
                    type: string
                    nullable: true
                    description: >-
                      User id of the approver. Set when an `NEEDS_APPROVAL` post
                      is approved.
                  approvedAt:
                    type: string
                    format: date-time
                    nullable: true
                    description: When the post was approved, if applicable.
                  createdViaApi:
                    type: boolean
                    description: >-
                      True when the post was authored by an API-key or OAuth
                      request. Cookie-session dashboard posts are false.
                  createdViaFlatShape:
                    type: boolean
                    description: >-
                      True when the request used the flat `platforms[]` body
                      shape. False for the nested `targets[]` shape and
                      dashboard posts.
                  deletedAt:
                    type: string
                    format: date-time
                    nullable: true
                    description: >-
                      Soft-delete timestamp. Listings and `GET /posts/:id`
                      exclude rows where this is non-null.
                  createdAt:
                    type: string
                    format: date-time
                    description: When the post was created.
                  updatedAt:
                    type: string
                    format: date-time
                    description: When the post was last modified.
                  targets:
                    description: >-
                      One fan-out target per connected account this post
                      publishes to.
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          description: Prefixed cuid identifier of this target.
                        postId:
                          type: string
                          description: Owning post id.
                        socialAccountId:
                          type: string
                          description: >-
                            Connected social account this target publishes to.
                            Same id returned from `GET /social-accounts`.
                        platform:
                          type: string
                          enum:
                            - INSTAGRAM
                            - FACEBOOK_PAGE
                            - X
                            - LINKEDIN_PERSON
                            - LINKEDIN_COMPANY
                            - TIKTOK_BUSINESS
                            - TIKTOK_PERSONAL
                            - YOUTUBE
                            - PINTEREST
                            - THREADS
                            - BLUESKY
                          description: >-
                            Platform of the bound social account, denormalised
                            for convenience.
                        status:
                          type: string
                          enum:
                            - DRAFT
                            - SCHEDULED
                            - PUBLISHING
                            - PUBLISHED
                            - FAILED
                            - SKIPPED
                            - CANCELED
                          description: >-
                            Per-target publish state. Independent of the parent
                            `Post.status` so one target can FAIL while others
                            PUBLISH.
                        captionOverride:
                          type: string
                          nullable: true
                          description: >-
                            Override of the post-level caption for this target
                            only. Null when the parent caption is used.
                        firstComment:
                          type: string
                          nullable: true
                          description: >-
                            First-comment text posted as a reply after the main
                            post lands. Null when no first comment was
                            requested.
                        firstCommentError:
                          type: string
                          nullable: true
                          description: >-
                            Set when the main post landed but the first-comment
                            leg failed (rate limit, missing scope, comments
                            disabled). Cleared on a successful retry.
                        firstCommentAttempt:
                          type: integer
                          description: >-
                            Monotonic count of first-comment attempts (publisher
                            leg + manual retries). Powers the retry-cooldown
                            gate without scanning `PublishAttempt`.
                        platformOptions:
                          type: object
                          additionalProperties: true
                          nullable: true
                          description: >-
                            Per-platform options discriminated on `platform`.
                            Shape mirrors what was passed in at create / update
                            time.
                        mediaIds:
                          description: >-
                            Per-target media override. Empty array means the
                            target inherits the post-level `media` ordering.
                          type: array
                          items:
                            type: string
                        scheduledFor:
                          type: string
                          format: date-time
                          nullable: true
                          description: >-
                            When this target is scheduled to publish. Null on
                            drafts.
                        publishedAt:
                          type: string
                          format: date-time
                          nullable: true
                          description: >-
                            When this target actually published. Null until the
                            publisher lands.
                        externalPostId:
                          type: string
                          nullable: true
                          description: >-
                            Stable per-platform post identifier returned by the
                            platform after publish. Null until the publisher
                            lands.
                        externalUrl:
                          type: string
                          nullable: true
                          description: >-
                            Public URL of the published post on the platform,
                            when the platform exposes one.
                        errorCode:
                          type: string
                          nullable: true
                          description: >-
                            Machine-readable error code from the last failed
                            publish attempt.
                        errorMessage:
                          type: string
                          nullable: true
                          description: >-
                            Human-readable error message from the last failed
                            publish attempt.
                        attemptCount:
                          type: integer
                          description: >-
                            Monotonic count of publish attempts the worker has
                            made for this target.
                        lastAttemptAt:
                          type: string
                          format: date-time
                          nullable: true
                          description: >-
                            Timestamp of the most recent publish attempt,
                            success or failure.
                        createdAt:
                          type: string
                          format: date-time
                          description: When this target row was created.
                        updatedAt:
                          type: string
                          format: date-time
                          description: When this target row was last modified.
                  media:
                    description: >-
                      Library media attached to the post, ordered by `order`.
                      Per-target overrides on `targets[].mediaIds` win over this
                      list.
                    type: array
                    items:
                      type: object
                      properties:
                        postId:
                          type: string
                          description: Owning post id.
                        mediaAssetId:
                          type: string
                          description: >-
                            Library `MediaAsset` id. The asset itself (storage
                            key, kind, etc.) is fetched via `GET /media/:id`.
                        order:
                          type: integer
                          description: Ordering position within the post (0-indexed).
                        altText:
                          type: string
                          nullable: true
                          description: >-
                            Per-post alt text override. Falls back to
                            `MediaAsset.altText` when null.
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode:
                    type: integer
                    example: 400
                  code:
                    type: string
                    example: VALIDATION_FAILED
                  message:
                    type: string
                  requestId:
                    type: string
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode:
                    type: integer
                    example: 401
                  message:
                    type: string
                    example: Unauthorized
                  requestId:
                    type: string
components:
  schemas:
    CreatePostFlatDto:
      type: object
      properties:
        content:
          type: string
          maxLength: 10000
          description: >-
            Default caption applied to every platform unless overridden via
            `platforms[].captionOverride`.
          example: Just shipped a new feature 🚀
        scheduledFor:
          type: string
          description: >-
            ISO-8601 publish time. Post is created as SCHEDULED and a Temporal
            workflow is started. Omit for a draft.
          example: '2026-06-15T09:00:00.000Z'
        draftScheduledFor:
          type: string
          description: >-
            ISO-8601 time to pin the post on the calendar without actually
            scheduling it (status stays DRAFT). Ignored when `scheduledFor` is
            set.
        timezone:
          type: string
          description: >-
            IANA timezone the user composed in (e.g. `Europe/Stockholm`). Used
            to render `scheduledFor` correctly in the UI; not used by the
            publisher.
        platforms:
          description: One entry per platform to publish to. Order is preserved in the UI.
          example:
            - accountId: soc_01HZW2K9R5T8V3N7M4P0J1Q6BD
              platformOptions:
                platform: INSTAGRAM
                kind: FEED
          type: array
          items:
            $ref: '#/components/schemas/FlatPlatformTargetDto'
        mediaItems:
          description: >-
            Media to ingest by URL. The server fetches each URL (SSRF-guarded)
            and stores it in your media library. Resulting `MediaAsset` ids are
            prepended to `mediaIds`.
          type: array
          items:
            $ref: '#/components/schemas/FlatMediaItemDto'
        mediaIds:
          description: >-
            IDs of media already in your library (returned from `POST
            /media/presign` or `POST /media/from-url`).
          type: array
          items:
            type: string
        mediaAltText:
          type: object
          description: >-
            Per-asset alt-text overrides keyed by `MediaAsset.id`. Falls back to
            `MediaAsset.altText` when an entry is absent.
      required:
        - platforms
    FlatPlatformTargetDto:
      type: object
      properties:
        accountId:
          type: string
          description: >-
            ID of the connected social account to publish to (returned from `GET
            /social-accounts`).
          example: soc_01HZW2K9R5T8V3N7M4P0J1Q6BD
        captionOverride:
          type: string
          maxLength: 10000
          description: Override the post-level caption for this platform only.
        firstComment:
          type: string
          maxLength: 2000
          description: >-
            Auto-posted as the first reply after the main post lands
            (IG/FB/LinkedIn/X/YouTube/Threads).
        platformOptions:
          type: object
          description: >-
            Per-platform options keyed by discriminator `platform`. Shape
            mirrors the legacy nested route — see `docs/platforms/<name>.mdx`
            for each platform's schema.
          example:
            platform: INSTAGRAM
            kind: FEED
        mediaIds:
          description: >-
            Override the post-level media for this platform only (e.g. send a
            video to TikTok but images to IG).
          type: array
          items:
            type: string
      required:
        - accountId
    FlatMediaItemDto:
      type: object
      properties:
        type:
          type: string
          enum:
            - IMAGE
            - VIDEO
            - GIF
            - DOCUMENT
          description: >-
            Media kind hint. Accepts either uppercase enum (`"IMAGE"`,
            `"VIDEO"`, `"GIF"`) or lowercase (`"image"`, `"video"`, `"gif"`) —
            the server normalises before validation.
        url:
          type: string
          example: https://cdn.example.com/launch-hero.jpg
          description: >-
            HTTPS URL the server will fetch. SSRF-protected — private/reserved
            IPs are rejected.
        altText:
          type: string
          maxLength: 1000
          description: Alt text persisted alongside this asset.
      required:
        - type
        - url
  securitySchemes:
    bearer:
      scheme: bearer
      bearerFormat: API key
      type: http
      description: Your Postbreeze API key

````