# Create a post

> Create a draft, or a scheduled post that publishes on its own.

**Source:** https://postprism.app/docs/api/create-post  
**Updated:** 2026-10-10

---

`POST https://studio.postprism.app/api/v1/posts`

Creates a post in the workspace. Without `scheduled_at` it is saved as a draft that waits on the Postprism calendar for someone to review and schedule. With `scheduled_at` it is scheduled and publishes automatically at that time.

Write one version per platform in `platform_content`. That is the text that gets published, so a short X post and a longer LinkedIn post can go out together.

## Request body

Content-Type: `application/json`

| Field | Type | Description |
| --- | --- | --- |
| `base_content` | string, required | The shared draft. It is what you see first in Postprism and the starting point for each version, but it is not what gets published. |
| `platforms` | string[], required | Platform keys to publish to, from `GET /api/v1/platforms` (for example `["linkedin", "twitter"]`). |
| `platform_content` | object, optional | One version per platform, keyed by platform key. Each needs `content`. Optional for drafts, but a scheduled post fails to publish to any platform without an entry here. |
| `scheduled_at` | date-time, optional | When to publish, as an ISO 8601 date-time (use UTC, for example `2026-10-16T09:30:00Z`). With it the post is `scheduled`; without it the post is saved as a `draft`. |
| `media` | object[], optional | Up to 10 images or videos, each uploaded first with `POST /api/v1/media`. They are attached to every platform version. |
| `workspace_id` | uuid, optional | Create the post in another workspace you belong to. Defaults to your key’s workspace. |

## Example

```bash
curl -X POST "https://studio.postprism.app/api/v1/posts" \
  -H "Authorization: Bearer pp_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
  "base_content": "Our autumn menu is here: maple oat latte, pumpkin cold brew and a new almond croissant.",
  "platforms": ["linkedin", "twitter"],
  "platform_content": {
    "linkedin": {
      "content": "Our autumn menu is here. Three new drinks, one new pastry, all made in-house at Juniper Roasters. Which one are you trying first?"
    },
    "twitter": {
      "content": "Autumn menu, now pouring. Maple oat latte first?",
      "hashtags": ["#autumnmenu", "#coffeeshop"]
    }
  },
  "media": [
    {
      "url": "https://…/launch-photo.webp",
      "type": "image"
    }
  ],
  "scheduled_at": "2026-10-16T09:30:00Z"
}'
```

## Response

Status `201`.

`data` is a `Post`: A full post, as returned when you create, read or update one. It has every `PostSummary` field plus the ones below. Ignore any other fields; they are not part of the stable API.

| Field | Type | Description |
| --- | --- | --- |
| `id` | uuid | The post ID. |
| `base_content` | string | The shared draft the per-platform versions start from. |
| `platforms` | string[] | Platform keys the post targets. |
| `platform_content` | object | Per-platform versions, keyed by platform key. |
| `status` | string | Where the post is in its lifecycle. One of: `draft`, `scheduled`, `publishing`, `published`, `failed`. |
| `scheduled_at` | date-time, nullable | When the post publishes, in UTC. `null` for drafts. |
| `published_at` | date-time, nullable | When the post was published, or `null`. |
| `media` | object[] | Attached images and videos. |
| `ai_generated` | boolean | Whether the post was written with Postprism AI. |
| `created_at` | date-time | When the post was created. |
| `workspace_id` | uuid | The workspace the post belongs to. |
| `user_id` | uuid | The member who created the post. |
| `updated_at` | date-time | When the post last changed. |

```json
{
  "data": {
    "id": "3f1c2a9e-0000-4000-8000-00000000a001",
    "workspace_id": "7b2d4e6f-0000-4000-8000-00000000b001",
    "user_id": "9a8b7c6d-0000-4000-8000-00000000c001",
    "base_content": "Our autumn menu is here: maple oat latte, pumpkin cold brew and a new almond croissant.",
    "platforms": ["linkedin", "twitter"],
    "platform_content": {
      "linkedin": {
        "content": "Our autumn menu is here. Three new drinks, one new pastry, all made in-house at Juniper Roasters. Which one are you trying first?"
      },
      "twitter": {
        "content": "Autumn menu, now pouring. Maple oat latte first?",
        "hashtags": ["#autumnmenu", "#coffeeshop"]
      }
    },
    "media": [
      {
        "url": "https://…/launch-photo.webp",
        "type": "image"
      }
    ],
    "status": "scheduled",
    "scheduled_at": "2026-10-16T09:30:00Z",
    "published_at": null,
    "ai_generated": false,
    "created_at": "2026-10-10T14:02:11Z",
    "updated_at": "2026-10-10T14:02:11Z"
  },
  "error": null
}
```

## Errors

| Status | Message | When |
| --- | --- | --- |
| 400 | `base_content and platforms are required.` | `base_content` is empty or `platforms` is missing or empty. |
| 400 | `media[0].url must be a URL returned by POST /api/v1/media.` | A media URL was not uploaded through the API by you. |
| 400 | `media accepts at most 10 items.` | More than 10 files were attached. |
| 400 | `platform_content.linkedin.media contains a URL that was not returned by POST /api/v1/media.` | A per-platform media URL (or a YouTube `thumbnailUrl`) was not uploaded through the API. |
| 400 | `platform_content.youtube.settings: YouTube title: YouTube titles are limited to 100 characters.` | A platform setting failed validation. The message names the field. |
| 401 | `Invalid or revoked API key` | The `Authorization` header is missing, malformed, or the key was revoked. |
| 404 | `Workspace not found, or you are not a member of it.` | The `workspace_id` you passed (or your key’s default workspace) is not one you belong to. |
| 429 | `Too many requests` | You went over the hourly limit. See Rate limits. |

## Notes

- Postprism publishes only to accounts already connected in the workspace. A platform with no connection fails with the message `Platform <key> not connected`, which you can read on the post in Postprism.
- Each network’s own rules apply when the post publishes, for example a Pinterest Pin needs an image. See the platform guides.
