---
title: "Create a new post"
method: POST
path: "/posts"
tags: ["Posts"]
---

# Create a new post

`POST /posts`

Creates a post in the specified workspace and page. Use `pageId` for a single post or `pageIds` to create grouped cross-page posts. When `media` URLs are provided for grouped posts, each file is imported into the workspace Media Library once and the same asset is reused across every post in the group instead of being copied per platform. The `notify` flag controls whether workspace members receive a post-added notification (email/in-app push); set it to `false` to suppress those notifications. Internal activity feed entries are always recorded. `notify` is not an approval request — use POST /posts/{id}/request-approval to notify approvers. The `media` field: Up to 20 public image or video URLs, each max 100MB. Files are downloaded server-side from the provided URLs. Use `videoThumbnail` to set a custom video thumbnail (cover); it requires a video in `media` that finishes transcoding during the request, otherwise the request returns 400 after the post is created — in that case, retry via PATCH /posts/{id} once the video is processed.

## Request body

- object
  - `workspaceId` string, required
  - `pageId` string
  - `pageIds` string[]
  - `text` string
  - `gridPosition` integer
  - `scheduledAt` string, date-time
  - `labels` string[]
  - `media` string[] — Up to 20 public image or video URLs, each max 100MB. Files are downloaded server-side from the provided URLs.
  - `teamOnly` boolean
  - `approved` boolean
  - `approvedBy` string
  - `publishAtScheduledDate` boolean
  - `firstComment` string
  - `internalNote` string
  - `youtubeTitle` string
  - `linkedinPdfTitle` string — LinkedIn PDF carousel title (`linkedinData.pdfTitle`). When set on a LinkedIn post with multiple images, also enables publishing as a PDF document carousel (`linkedinData.publishCarouselAsPdf`). Pass an empty string on PATCH to disable PDF mode and clear the title.
  - `linkedinVideoTitle` string
  - `notify` boolean — Controls whether workspace members receive a post-added notification (email/in-app push). This is not an approval request — use POST /posts/{id}/request-approval to notify approvers.
  - `pinterest` object
    - `boardId` string, required
    - `title` string
    - `link` string, uri
    - `description` string
  - `campaignId` string, nullable
  - `videoThumbnail` object — Sets a custom thumbnail on the post video (the single video, or the first video for mixed media). Requires the video to be fully transcoded.
    - `imageUrl` string, uri — Public URL of a static image that is uploaded and set as the video thumbnail (cover).
    - `offsetSeconds` number — Offset into the video, in seconds; the frame at this position is extracted and set as the thumbnail.

## Response `201`

Post created

- object
  - `posts` object[], required
    - `id` string, required
    - `workspaceId` string, required
    - `pageId` string, required
    - `type` string, required
    - `classification` string, required
    - `plainText` string, required
    - `createdAt` string, date-time, required
    - `gridPosition` number
    - `campaignId` string, nullable, required
    - `media` string[], required — Up to 20 public image or video URLs, each max 100MB. Files are downloaded server-side from the provided URLs.
    - `scheduledAt` string, date-time, nullable, required
    - `status` string, required
    - `approved` boolean, required
    - `approvedBy` object[]
      - `userId` string, required
      - `approvedAt` string, date-time, required
      - `levelId` string
    - `approval` object, required
      - `status` 'NOT_APPLICABLE' | 'NEVER_SENT' | 'PENDING' | 'PARTIALLY_APPROVED' | 'FULLY_APPROVED', required
      - `approved` boolean, required
      - `type` 'NONE' | 'OPTIONAL' | 'REQUIRED' | 'MULTIPLE', required
      - `completedLevels` integer, required
      - `totalLevels` integer, required
      - `currentLevelId` string
      - `levels` object[], required
        - `id` string, required
        - `label` string, required
        - `approved` boolean, required
        - `approvedBy` object[], required
          - `userId` string, required
          - `approvedAt` string, date-time, required
          - `levelId` string
    - `published` boolean, required
    - `scheduledSet` boolean, required
    - `teamOnly` boolean, required
    - `archived` boolean, required
    - `modifiedAt` string, date-time
    - `mediaType` string
    - `videoThumbnailUrl` string, uri — Current thumbnail (cover) URL of the post video, when the post has a video with a thumbnail.
    - `labels` object[]
      - `uuid` string, required
      - `text` string, required
      - `color` string, required
    - `commentsCounter` number, required
    - `notesCounter` number, required
    - `publicShareLink` string, uri
    - `publishedPostLink` string, uri
    - `groupId` string
    - `groupPageIds` string[]
    - `groupSync` boolean
    - `pinterest` object
      - `boardId` string, required
      - `boardName` string, required
      - `title` string, nullable, required
      - `link` string, nullable, required
      - `description` string, nullable, required

## Other responses

- `400` — Validation error
- `401` — Unauthorized
- `403` — Forbidden
- `404` — Workspace or page not found
- `429` — Rate limit exceeded
- `500` — Internal server error

---

[API](https://skmtc.net/planable/apis/planable-public-api.md) · [All operations](https://skmtc.net/planable/apis/planable-public-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/planable/planable-public-api/revisions/e91a4f756dfe/schema)
