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

# Create a new post

> Create a new post in your publication. The publication is identified by the API key provided in the Authorization header.

**Requirements:**
- `title` field is required
- Provide content as either `markdown` (converted to TipTap JSON) OR `bodyJson` (a Tiptap document for content with buttons/linked images) — exactly one is required, not both

**Behavior:**
- The post will be created as published by default. Set `status` to `"draft"` to create a draft instead
- If `sendNewsletter` is true, an email will be sent to all subscribers when the post publishes
- Set `scheduledAt` (Unix timestamp in milliseconds) to schedule first-publish for a future time. Must be in the future and at most 30 days out. Scheduling cannot be combined with `status: "draft"`. When scheduled, the response `status` is `"scheduled"` and the post publishes (plus sends newsletter, if requested) at the scheduled time.



## OpenAPI

````yaml /paragraph-api/openapi.json post /v1/posts
openapi: 3.1.0
info:
  title: Paragraph API
  version: 1.0.0
  description: >-
    Public API for interacting with Paragraph publications, posts, users, and
    coined writing.


    ## Rate Limiting

    API requests are rate-limited to ensure fair usage. Contact
    support@paragraph.com for higher limits.


    ## Pagination

    List endpoints support cursor-based pagination using `cursor` and `limit`
    parameters.
  contact:
    name: Paragraph Support
    email: support@paragraph.com
    url: https://paragraph.com/support
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT
servers:
  - url: https://public.api.paragraph.com/api
    description: Production server
security:
  - {}
tags:
  - name: publications
    description: Operations related to publications
  - name: posts
    description: Operations related to posts and content
  - name: users
    description: Operations related to users and authors
  - name: coins
    description: Operations related to tokenized content
  - name: subscribers
    description: Operations related to subscriber management (requires API key)
paths:
  /v1/posts:
    post:
      tags:
        - posts
      summary: Create a new post
      description: >-
        Create a new post in your publication. The publication is identified by
        the API key provided in the Authorization header.


        **Requirements:**

        - `title` field is required

        - Provide content as either `markdown` (converted to TipTap JSON) OR
        `bodyJson` (a Tiptap document for content with buttons/linked images) —
        exactly one is required, not both


        **Behavior:**

        - The post will be created as published by default. Set `status` to
        `"draft"` to create a draft instead

        - If `sendNewsletter` is true, an email will be sent to all subscribers
        when the post publishes

        - Set `scheduledAt` (Unix timestamp in milliseconds) to schedule
        first-publish for a future time. Must be in the future and at most 30
        days out. Scheduling cannot be combined with `status: "draft"`. When
        scheduled, the response `status` is `"scheduled"` and the post publishes
        (plus sends newsletter, if requested) at the scheduled time.
      operationId: createPost
      parameters: []
      requestBody:
        description: Body
        content:
          application/json:
            schema:
              type: object
              properties:
                markdown:
                  type: string
                  description: >-
                    Post content in Markdown format. Provide `markdown` OR
                    `bodyJson`, not both. Markdown cannot represent buttons or
                    linked images — use `bodyJson` for those.
                bodyJson:
                  type: string
                  description: >-
                    Post content as a Tiptap document, JSON-stringified (e.g.
                    '{"type":"doc","content":[...]}'). Use instead of `markdown`
                    when the body needs Subscribe/Share/custom buttons or linked
                    images. Validated server-side; an invalid document is
                    rejected. Provide `markdown` OR `bodyJson`, not both.
                title:
                  type: string
                  maxLength: 200
                  description: Title of the post
                subtitle:
                  type: string
                  maxLength: 300
                  description: Optional subtitle or brief summary
                imageUrl:
                  type: string
                  format: uri
                  description: Optional URL to the post's cover image
                sendNewsletter:
                  oneOf:
                    - type: boolean
                    - type: string
                      enum:
                        - 'true'
                        - 'false'
                        - '1'
                        - '0'
                  description: >-
                    Whether to send an email newsletter to subscribers. Default:
                    false
                status:
                  type: string
                  enum:
                    - published
                    - draft
                  description: 'Status of the post. Default: published'
                slug:
                  type: string
                  minLength: 1
                  maxLength: 256
                  description: >-
                    Optional URL-friendly identifier for the post. If not
                    provided, will be generated from title
                postPreview:
                  type: string
                  maxLength: 500
                  description: >-
                    Optional preview text for the post. If not provided, will be
                    generated from content
                categories:
                  oneOf:
                    - type: array
                      items:
                        type: string
                    - type: string
                  description: >-
                    Optional array of category tags for the post. Can also be a
                    comma-separated string.
                scheduledAt:
                  description: >-
                    Optional Unix timestamp (milliseconds) to schedule
                    first-publish of the post at a future time. Must be in the
                    future. Cannot be combined with status: 'draft'. When set,
                    the post is created and queued to publish (and send
                    newsletter, if requested) at the specified time. Pass 0 or
                    omit the field for an unscheduled post.
                  type: integer
                  minimum: 0
              required:
                - title
      responses:
        '200':
          description: Post created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    description: The ID of the created post
                  status:
                    type: string
                    enum:
                      - published
                      - draft
                      - scheduled
                    description: >-
                      Final status of the post: 'published' if published
                      immediately, 'draft' if created as a draft, 'scheduled' if
                      queued to publish at scheduledAt
                required:
                  - id
                  - status
        '400':
          description: Invalid request - check required fields
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - false
                    description: Always false for error responses
                  msg:
                    type: string
                    description: Human-readable error message
                required:
                  - success
                  - msg
        '401':
          description: Invalid or missing API key
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - false
                    description: Always false for error responses
                  msg:
                    type: string
                    description: Human-readable error message
                required:
                  - success
                  - msg
        '404':
          description: Publication not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - false
                    description: Always false for error responses
                  msg:
                    type: string
                    description: Human-readable error message
                required:
                  - success
                  - msg
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - false
                    description: Always false for error responses
                  msg:
                    type: string
                    description: Human-readable error message
                required:
                  - success
                  - msg
      security:
        - apiKey: []
      x-codeSamples:
        - lang: typescript
          label: Create and publish a post
          source: |-
            import { ParagraphAPI } from "@paragraph-com/sdk"

            const api = new ParagraphAPI({ apiKey: "your-api-key" })
            const { id, status } = await api.posts.create({
              title: "My First Post",
              markdown: "# Hello World\n\nThis is my first post!",
              sendNewsletter: true
            })
            // status: "published"
        - lang: typescript
          label: Create a draft
          source: |-
            import { ParagraphAPI } from "@paragraph-com/sdk"

            const api = new ParagraphAPI({ apiKey: "your-api-key" })
            const { id, status } = await api.posts.create({
              title: "Work in Progress",
              markdown: "# Draft\n\nStill working on this.",
              status: "draft"
            })
            // status: "draft"
        - lang: typescript
          label: Schedule a post for a future time
          source: |-
            import { ParagraphAPI } from "@paragraph-com/sdk"

            const api = new ParagraphAPI({ apiKey: "your-api-key" })
            const { id, status } = await api.posts.create({
              title: "Launch Announcement",
              markdown: "# We're launching tomorrow!",
              scheduledAt: Date.now() + 24 * 60 * 60 * 1000,
              sendNewsletter: true,
            })
            // status: "scheduled"
        - lang: bash
          label: Create post using curl
          source: |-
            curl -X POST "https://public.api.paragraph.com/api/v1/posts" \
              -H "Authorization: Bearer your-api-key" \
              -H "Content-Type: application/json" \
              -d '{"title": "My First Post", "markdown": "# Hello World"}'
components:
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: >-
        API key for authenticating protected endpoints. Pass as Bearer token in
        Authorization header.

````