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

# Create a post

> Creates a post on one or more channels.

`posts` carries one entry per channel. Each entry names its integration
and its own `value` array, so the same call can send tailored copy to
every channel rather than one message everywhere.

`type` decides what happens next:

- `schedule` — queued for `date`.
- `now` — published immediately.
- `draft` — saved, never published. Drafts skip settings validation,
  so this is the way to park an incomplete post.




## OpenAPI

````yaml public-api/openapi.yaml POST /posts
openapi: 3.1.0
info:
  title: Nushir Public API
  version: 1.0.0
  description: >
    Schedule, publish and measure social posts on Nushir from your own code.


    Every route below is derived from the running application

    (`public.integrations.controller.ts`), so this document describes what the

    API actually does rather than what it is intended to do.


    ## Base URL


    ```

    https://platform.nushir.com/api/public/v1

    ```


    ## Authentication


    Send your key in the `Authorization` header. There is no `Bearer` prefix.


    ```

    Authorization: your-api-key

    ```


    Two kinds of credential are accepted on the same header:


    - **An API key**, created in *Settings → Developers*. It is scoped to the
      organisation that created it.
    - **An OAuth token**, issued to an approved app. These are recognised by
      their `pos_` prefix and resolve to the organisation that granted access.

    A missing or unrecognised credential returns `401`.


    ## Rate limits


    **90 requests per hour** per organisation, counted across every endpoint.

    Crossing the limit returns `429`; the window is one hour from each request.


    ## Try it from these pages


    Every endpoint page has a runnable panel. Paste your API key into the

    `Authorization` field, fill the parameters, and send - the request runs

    against your real organisation, so anything you create or delete is real.


    ## Channel or integration?


    The interface says **channel**. The API says **integration**. They are the

    same object; the name simply never got reconciled. Anywhere this document

    says *integration*, the calendar calls it a channel.


    ## Dates


    All dates are ISO-8601 in **UTC**. A post scheduled for
    `2026-09-01T09:00:00Z`

    publishes at 09:00 UTC regardless of the timezone on the account.


    ## Errors


    | Status | Meaning |

    |---|---|

    | `400` | The body failed validation. The response names the offending
    fields. |

    | `401` | Missing or invalid `Authorization` header. |

    | `403` | Authenticated, but the plan does not permit the action. |

    | `404` | No such object **in your organisation**. |


    A `404` is returned rather than `403` when an object exists but belongs to

    someone else, so the API never confirms that another organisation's id is

    real.
servers:
  - url: https://platform.nushir.com/api/public/v1
    description: Production
security:
  - apiKey: []
tags:
  - name: Integrations
    description: The connected social channels.
  - name: Posts
    description: Create, schedule, inspect and delete posts.
  - name: Uploads
    description: Get media into the library so a post can reference it.
  - name: Analytics
    description: Performance figures, where the platform reports them.
  - name: Notifications
    description: Account-level messages.
  - name: Video
    description: Generated video, where enabled.
paths:
  /posts:
    post:
      tags:
        - Posts
      summary: Create a post
      description: |
        Creates a post on one or more channels.

        `posts` carries one entry per channel. Each entry names its integration
        and its own `value` array, so the same call can send tailored copy to
        every channel rather than one message everywhere.

        `type` decides what happens next:

        - `schedule` — queued for `date`.
        - `now` — published immediately.
        - `draft` — saved, never published. Drafts skip settings validation,
          so this is the way to park an incomplete post.
      operationId: createPost
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - type
                - posts
              properties:
                type:
                  type: string
                  enum:
                    - schedule
                    - now
                    - draft
                date:
                  type: string
                  format: date-time
                  description: Required when `type` is `schedule`. UTC.
                shortLink:
                  type: boolean
                  description: Rewrite links through the short-link service.
                tags:
                  type: array
                  items:
                    type: string
                posts:
                  type: array
                  minItems: 1
                  items:
                    $ref: '#/components/schemas/PostGroup'
            examples:
              schedule:
                summary: Schedule one video to TikTok
                value:
                  type: schedule
                  date: '2026-09-01T09:00:00Z'
                  posts:
                    - integration:
                        id: clx7h2k9a0001
                      value:
                        - content: Three channels, one calendar.
                          image:
                            - id: med_01H9
                      settings:
                        __type: tiktok
                        privacy_level: PUBLIC_TO_EVERYONE
                        content_posting_method: DIRECT_POST
              draft:
                summary: Park a draft, no settings needed
                value:
                  type: draft
                  posts:
                    - integration:
                        id: clx7h2k9a0001
                      value:
                        - content: Something for later.
      responses:
        '200':
          description: Created.
        '400':
          description: |
            Validation failed. The most common causes are a missing `settings`
            object for a channel that requires one, and a post with no media on
            a platform that will not accept text alone.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: The plan's monthly post allowance is exhausted.
components:
  schemas:
    PostGroup:
      type: object
      required:
        - integration
        - value
      properties:
        integration:
          type: object
          required:
            - id
          properties:
            id:
              type: string
        value:
          type: array
          minItems: 1
          description: >-
            One entry per part of the post. A single entry is an ordinary post;
            several entries make a thread on platforms that support one, and
            become follow-up comments on those that do not.
          items:
            $ref: '#/components/schemas/PostContent'
        group:
          type: string
          description: >-
            Identifies posts created together across several channels, so they
            can be deleted or rescheduled as one unit.
        settings:
          type: object
          description: >-
            Platform-specific options for this channel. The required shape
            depends on the channel's `identifier` — see **Channel settings**.
          additionalProperties: true
    Error:
      type: object
      properties:
        statusCode:
          type: integer
        message:
          oneOf:
            - type: string
            - type: array
              items:
                type: string
        error:
          type: string
    PostContent:
      type: object
      required:
        - content
      properties:
        content:
          type: string
          description: >-
            The body of this part of the post, as HTML. It is sanitised on
            arrival, so unsupported markup is stripped rather than rejected.
        id:
          type: string
          description: Present when updating an existing part.
        image:
          type: array
          items:
            $ref: '#/components/schemas/MediaItem'
    MediaItem:
      type: object
      required:
        - id
      properties:
        id:
          type: string
          description: An id returned by one of the upload routes.
        path:
          type: string
          description: Public URL of the stored file.
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: Authorization
      description: |
        Your API key from *Settings → Developers*, or an OAuth token beginning
        `pos_`. Sent raw — do **not** prefix it with `Bearer`.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.