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

# Create Post

> Schedule or publish text-only, video, or slideshow posts to connected accounts.

Schedule or publish immediately to one or more connected accounts.

## Before you post

1. Use an API key for a workspace with an active **Creator, Professional, or Business** subscription.
2. Call [`GET /accounts`](/api-reference/get-accounts) and pick account UUIDs.
3. Check each account's `capabilities.supported_content_kinds` and `caption_limit`.
4. Build the payload below. Only include provider settings for platforms you are actually targeting.

<Tip>
  Omit `media` or set it to `null` only when **every** selected account supports
  `text_only`.
</Tip>

## Request body

<ParamField body="caption" type="string" required>
  Shared caption text. Final length is checked per targeted account after lookup
  (hosted accounts: 500 chars max).
</ParamField>

<ParamField body="accounts" type="array" required>
  One to ten account objects: `[{ "id": "<uuid-from-/accounts>" }]`.
</ParamField>

<ParamField body="media" type="object | null">
  Optional. `video`, `slideshow`, or `null`/omit for text-only posts.

  <Expandable title="Video">
    <ParamField body="type" type="string" required>`video`</ParamField>
    <ParamField body="url" type="string" required>Direct MP4/MOV/M4V/AVI URL. Google Drive links work.</ParamField>

    <ParamField body="duration_sec" type="number">
      Duration in seconds. Also accepts `duration_seconds`, `duration`, `durationSec`, or
      `video_duration_sec`. **Required** for non-premium X video posts.
    </ParamField>

    <ParamField body="bytes" type="number">Optional size in bytes. Also accepts `size`.</ParamField>
    <ParamField body="width" type="number">Optional width in pixels.</ParamField>
    <ParamField body="height" type="number">Optional height in pixels.</ParamField>
    <ParamField body="mime_type" type="string">Optional MIME type. Alias: `mime`.</ParamField>

    <ParamField body="metadata" type="object">
      Optional nested object that can repeat `width`, `height`, `mime_type`, and `bytes`.
    </ParamField>
  </Expandable>

  <Expandable title="Slideshow">
    <ParamField body="type" type="string" required>`slideshow`</ParamField>
    <ParamField body="urls" type="string[]" required>1–35 JPG/JPEG/PNG image URLs, in order.</ParamField>
  </Expandable>
</ParamField>

<ParamField body="scheduled_at" type="string">
  ISO 8601 datetime **with timezone offset** (for example `2026-05-21T15:00:00Z`).
  Omit or send a time within 30 seconds of now for immediate publish (`status: pending`).
  For true scheduled posts, the time must be **at least 2 minutes** in the future.
</ParamField>

<ParamField body="external_id" type="string">
  Recommended idempotency key (max 128 chars). Same key + same payload replays the original
  post (`200`, `duplicate: true`). Same key + different payload returns `409 create_failed`.
  If omitted, the API dedupes from a SHA-256 fingerprint of the request body instead; a conflicting
  replay also returns `409 create_failed`.
</ParamField>

<ParamField body="music_url" type="string">
  TikTok-only. A TikTok post URL used to resolve the track. Rejected when any non-TikTok account
  is selected, including Instagram.
</ParamField>

## Provider settings

Use **`settings.<provider>`** for X, Instagram, Facebook, LinkedIn, Bluesky,
and YouTube.

For TikTok and Pinterest on **create**, use the top-level **`tiktok`** and **`pinterest`**
objects — not `settings.tiktok` or `settings.pinterest`. Top-level fields run the full
create-time validation (BYO-only TikTok, hosted TikTok rejection, `MEDIA_UPLOAD` rules, and
field limits).

Only send settings for providers present in your `accounts` list. Unknown `settings` keys return
`422 invalid_payload`.

<Warning>
  `capabilities.settings_schema` from [`GET /accounts`](/api-reference/get-accounts) reflects the
  dashboard composer, not always the Partner API field names. Use the tables below when building
  create payloads.
</Warning>

### YouTube — `settings.youtube`

Requires a **video** post to a YouTube account.

| Field                     | Type   | Required | Notes                                                                                                             |
| ------------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------- |
| `title`                   | string | No       | Max 100 chars. If omitted, derived from `settings.youtube.description`, then `caption` (first non-empty line).    |
| `description`             | string | No       | Overrides `caption` as the YouTube description when set.                                                          |
| `type`                    | string | No       | Visibility: `public`, `private`, or `unlisted`. Default `public`. Alias: `privacy`.                               |
| `privacy`                 | string | No       | Same as `type`.                                                                                                   |
| `tags`                    | array  | No       | `{ "value": "...", "label": "..." }` items. Publish uses `label` values. Total tag length capped at publish time. |
| `categoryId`              | string | No       | YouTube category ID.                                                                                              |
| `selfDeclaredMadeForKids` | string | No       | `yes` or `no`. Default `no`. Boolean alias: `madeForKids`.                                                        |
| `thumbnail`               | object | No       | Custom thumbnail: `{ "path": "<image-url>" }`.                                                                    |

### TikTok — top-level `tiktok`

Requires **BYO** TikTok accounts and media (video or slideshow). Hosted TikTok accounts cannot use
TikTok-specific settings.

For **video** posts, the merged publish text built from `caption`, `tiktok.title`, and
`tiktok.description` must stay **≤ 2,200 characters combined**.

| Field                      | Type    | Notes                                                                                                            |
| -------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------- |
| `title`                    | string  | Video: max 2,200 chars. Slideshow: max 90 chars.                                                                 |
| `description`              | string  | Slideshow: max 4,000 chars. Video: used as the publish body when `caption` is empty.                             |
| `post_mode`                | string  | `DIRECT_POST` or `MEDIA_UPLOAD` (slideshow drafts only). Defaults to `DIRECT_POST` at publish time when omitted. |
| `privacy_level`            | string  | `PUBLIC_TO_EVERYONE`, `MUTUAL_FOLLOW_FRIENDS`, `FOLLOWER_OF_CREATOR`, `SELF_ONLY`.                               |
| `music_usage_confirmation` | boolean | Confirms the user has accepted TikTok's music-usage terms for this post. Preferred Partner API field.            |
| `user_consent`             | boolean | Legacy alias for `music_usage_confirmation`.                                                                     |
| `disable_comment`          | boolean | Inverted to allow/deny comments.                                                                                 |
| `disable_duet`             | boolean | Video only.                                                                                                      |
| `disable_stitch`           | boolean | Video only.                                                                                                      |
| `auto_add_music`           | boolean | Slideshow only.                                                                                                  |
| `is_your_brand`            | boolean | Own-brand commercial content.                                                                                    |
| `is_branded_content`       | boolean | Third-party promotion.                                                                                           |
| `video_cover_timestamp_ms` | integer | Video `DIRECT_POST` only. Frame offset in milliseconds for the TikTok thumbnail.                                 |

### Pinterest — top-level `pinterest`

Requires at least one Pinterest account and image media.

| Field      | Type      | Notes                                                                                                      |
| ---------- | --------- | ---------------------------------------------------------------------------------------------------------- |
| `board_id` | string    | Pinterest board ID. Required for a successful pin publish — no account default is applied. Max 128 chars.  |
| `title`    | string    | Optional pin title. Max 100 chars.                                                                         |
| `link`     | string    | Optional destination URL. Max 2,048 chars.                                                                 |
| `tags`     | string\[] | Up to 30 tags, 1–100 chars each. Appended to the pin description; total description must stay ≤ 800 chars. |

### X — `settings.x` or `settings.twitter`

| Field                | Type    | Required | Notes                                                                           |
| -------------------- | ------- | -------- | ------------------------------------------------------------------------------- |
| `who_can_reply_post` | string  | No       | `everyone` (default), `following`, `mentionedUsers`, `subscribers`, `verified`. |
| `community`          | string  | No       | X community URL: `https://x.com/i/communities/<id>`.                            |
| `made_with_ai`       | boolean | No       | Default `false`.                                                                |
| `paid_partnership`   | boolean | No       | Default `false`.                                                                |

### Instagram — `settings.instagram` or `settings.instagram-standalone`

Both keys map to the same stored settings. If both are sent, `instagram-standalone` wins.

| Field                 | Type    | Required    | Notes                                                                                                                                                                                          |
| --------------------- | ------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `post_type`           | string  | Recommended | `post` (feed/reel) or `story`.                                                                                                                                                                 |
| `is_trial_reel`       | boolean | No          | Trial reel flag for video posts.                                                                                                                                                               |
| `graduation_strategy` | string  | No          | `MANUAL` or `SS_PERFORMANCE` when using trial reels.                                                                                                                                           |
| `collaborators`       | array   | No          | `[{ "label": "<username>" }]`. Ignored for stories.                                                                                                                                            |
| `cover_url`           | string  | No          | Custom Reel cover image URL. Takes priority over `thumb_offset_ms`. Video `post_type: post` only. Must be publicly accessible. **BYO Instagram only** — hosted accounts reject cover settings. |
| `thumb_offset_ms`     | integer | No          | Reel thumbnail frame offset in milliseconds when `cover_url` is omitted. Video `post_type: post` only. **BYO Instagram only.**                                                                 |
| `share_to_feed`       | boolean | No          | Share the Reel to the main feed. Default `true`. Set `false` for Reels tab only. **BYO Instagram only.**                                                                                       |

### Facebook — `settings.facebook`

| Field | Type   | Required | Notes                                     |
| ----- | ------ | -------- | ----------------------------------------- |
| `url` | string | No       | Optional link attachment URL on the post. |

### LinkedIn — `settings.linkedin` or `settings.linkedin-page`

Both keys map to the same stored settings. If both are sent, `linkedin-page` wins.

| Field                     | Type    | Required | Notes                                                |
| ------------------------- | ------- | -------- | ---------------------------------------------------- |
| `post_as_images_carousel` | boolean | No       | Post multi-image content as a LinkedIn carousel/PDF. |
| `carousel_name`           | string  | No       | Carousel/PDF title. Default `slides`.                |

### Bluesky — `settings.bluesky`

No provider-specific fields. Send `{}` or omit.

## Settings key reference

| Request key                     | Alias                | Stored as           |
| ------------------------------- | -------------------- | ------------------- |
| `settings.x`                    | `settings.twitter`   | `xSettings`         |
| `settings.instagram-standalone` | `settings.instagram` | `instagramSettings` |
| `settings.linkedin-page`        | `settings.linkedin`  | `linkedinSettings`  |
| Top-level `tiktok`              | —                    | `tikTokSettings`    |
| Top-level `pinterest`           | —                    | `pinterestSettings` |

## Limits (quick reference)

* **Video:** MP4/MOV/M4V/AVI, under 100MB. Hosted accounts: 15–60s when duration is provided.
* **Non-premium X video:** duration metadata required; max 140 seconds.
* **Slideshow:** 1–35 images, each under 5MB.
* **Caption caps (BYO):** X 280 (4,000 for premium accounts); Instagram 2,200; TikTok video 2,200 / photo description 4,000; LinkedIn 3,000; Pinterest 800; YouTube 5,000 bytes; Facebook 63,206.

## Response

Fresh creates return `201`. Idempotent replays return `200`.

```json theme={null}
{
  "ok": true,
  "code": 201,
  "message": "Post scheduled",
  "data": {
    "id": "11111111-1111-1111-1111-111111111111",
    "status": "scheduled",
    "scheduled_at": "2026-05-21T15:00:00Z",
    "warnings": []
  }
}
```

`duplicate: true` appears on idempotent replays. `warnings` are non-blocking (for example missing
video duration metadata).

## Examples

<RequestExample>
  ```bash Video to YouTube theme={null}
  curl --request POST \
    --url https://www.genviral.io/api/partner/v1/posts \
    --header 'Authorization: Bearer <token>' \
    --header 'Content-Type: application/json' \
    --data '{
    "caption": "Weekly product recap and what shipped this sprint.",
    "media": {
      "type": "video",
      "url": "https://cdn.example.com/recap.mp4",
      "duration_sec": 42
    },
    "accounts": [{ "id": "YOUR_YOUTUBE_ACCOUNT_ID" }],
    "settings": {
      "youtube": {
        "title": "Weekly product recap",
        "type": "public"
      }
    },
    "external_id": "yt-recap-2026-05-21"
  }'
  ```

  ```bash TikTok slideshow draft theme={null}
  curl --request POST \
    --url https://www.genviral.io/api/partner/v1/posts \
    --header 'Authorization: Bearer <token>' \
    --header 'Content-Type: application/json' \
    --data '{
    "caption": "3 outfits for the long weekend",
    "media": {
      "type": "slideshow",
      "urls": [
        "https://cdn.example.com/look-1.jpg",
        "https://cdn.example.com/look-2.jpg",
        "https://cdn.example.com/look-3.jpg"
      ]
    },
    "accounts": [{ "id": "YOUR_TIKTOK_BYO_ACCOUNT_ID" }],
    "tiktok": {
      "post_mode": "MEDIA_UPLOAD",
      "music_usage_confirmation": true,
      "privacy_level": "SELF_ONLY"
    },
    "external_id": "tiktok-draft-001"
  }'
  ```

  ```bash Pinterest pin theme={null}
  curl --request POST \
    --url https://www.genviral.io/api/partner/v1/posts \
    --header 'Authorization: Bearer <token>' \
    --header 'Content-Type: application/json' \
    --data '{
    "caption": "Minimal kitchen organization ideas that actually stick.",
    "media": {
      "type": "slideshow",
      "urls": ["https://cdn.example.com/pin-cover.jpg"]
    },
    "accounts": [{ "id": "YOUR_PINTEREST_ACCOUNT_ID" }],
    "pinterest": {
      "board_id": "YOUR_BOARD_ID",
      "link": "https://example.com/kitchen-guide",
      "tags": ["kitchen organization", "home tips"]
    },
    "external_id": "pinterest-pin-001"
  }'
  ```

  ```bash Instagram Reel cover theme={null}
  curl --request POST \
    --url https://www.genviral.io/api/partner/v1/posts \
    --header 'Authorization: Bearer <token>' \
    --header 'Content-Type: application/json' \
    --data '{
    "caption": "Behind the scenes from today'\''s shoot.",
    "media": {
      "type": "video",
      "url": "https://cdn.example.com/reel.mp4"
    },
    "accounts": [{ "id": "YOUR_INSTAGRAM_BYO_ACCOUNT_ID" }],
    "settings": {
      "instagram": {
        "post_type": "post",
        "cover_url": "https://cdn.example.com/reel-cover.jpg",
        "share_to_feed": false
      }
    },
    "external_id": "instagram-reel-cover-001"
  }'
  ```

  ```bash Text-only X post theme={null}
  curl --request POST \
    --url https://www.genviral.io/api/partner/v1/posts \
    --header 'Authorization: Bearer <token>' \
    --header 'Content-Type: application/json' \
    --data '{
    "caption": "Ship the repeatable thing, not the busywork.",
    "accounts": [{ "id": "YOUR_X_ACCOUNT_ID" }],
    "media": null,
    "settings": {
      "x": {
        "who_can_reply_post": "everyone"
      }
    }
  }'
  ```
</RequestExample>

## Errors

| Code                        | When                                                                            |
| --------------------------- | ------------------------------------------------------------------------------- |
| `422 invalid_payload`       | Schema validation failed (includes `issues` array)                              |
| `400 invalid_json`          | Request body is not valid JSON                                                  |
| `400 validation_failed`     | Caption, media, music, TikTok/Pinterest, or schedule rules failed               |
| `400 unknown_accounts`      | Account ID outside key scope                                                    |
| `400 media_unreachable`     | Media URL not reachable                                                         |
| `400 invalid_music_url`     | Invalid or non-TikTok music URL                                                 |
| `401`                       | Missing or invalid API key                                                      |
| `402 subscription_required` | No active Creator, Professional, or Business subscription                       |
| `403 subscription_required` | Hosted TikTok posting without an active TikTok virtual subscription             |
| `403 tier_not_allowed`      | Scheduler tier blocked                                                          |
| `409 create_failed`         | Same `external_id` or dedupe fingerprint reused with a different create payload |
| `500 create_failed`         | Unexpected upstream failure                                                     |
