> For the complete documentation index, see [llms.txt](https://help.contouron.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.contouron.com/api/post.md).

# Post

> For the complete documentation index, see [llms.txt](https://help.contouron.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.contouron.com/api/publish-post.md).

## Post

### Publishing a Post

#### Endpoint

**Base URL:** `https://backend.contouron.com/v2`

**URL:** `/posts`

**Method:** `POST`

**Rate Limit:** 30 requests / minute

#### Description

Publish a new post to a social media platform. The request must include the post content, target platform, and an `accountId` (fetched from `GET /v2/users/me/accounts`).

After submitting, poll Get Post Status with the returned `postSubmissionId` to track publishing progress.

#### Before You Start

1. Fetch your connected accounts: `GET /v2/users/me/accounts` (docs)
2. Fetch your subaccounts to get `pageId` for Facebook/LinkedIn and `playlistIds` for YouTube: `GET /v2/users/me/accounts/{accountId}/subaccounts` (docs).
3. Set `content.platform` and `target.targetType` to the same platform value (e.g., both `"twitter"`)

***

#### Request Body

The request body has two top-level fields: `post` (required) and optional scheduling fields. Do not nest scheduling fields inside `post`.

| Field             | Type      | Required | Description                                                                                                                            |
| ----------------- | --------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `post`            | `object`  | Yes      | The post content and metadata.                                                                                                         |
| `scheduledTime`   | `string`  | No       | ISO 8601 timestamp with timezone offset (e.g., `2026-03-04T16:30:00+00:00`). If provided, `useNextFreeSlot` is ignored.                |
| `useNextFreeSlot` | `boolean` | No       | Schedule at the next available slot time. Defaults to `false`. Requires at least one calendar slot configured for the target platform. |

**Scheduling behavior:**

* If `scheduledTime` is set: the post is scheduled for that time. `useNextFreeSlot` is ignored.
* If `useNextFreeSlot` is `true` (and no `scheduledTime`): the post is scheduled at the next available calendar slot for that platform.
* If neither `scheduledTime` nor `useNextFreeSlot` is provided: **the post publishes immediately.**
* Both fields must be **root-level** (siblings of `post`). If they are nested inside `post`, `options`, or any other object, they are ignored and the post publishes immediately.

#### `post` Object

| Field       | Type     | Required | Description                                                           |
| ----------- | -------- | -------- | --------------------------------------------------------------------- |
| `accountId` | `string` | Yes      | The account ID from `GET /v2/users/me/accounts`.                      |
| `content`   | `object` | Yes      | The content of the post. See `content` below.                         |
| `target`    | `object` | Yes      | The target platform and platform-specific fields. See `target` below. |

#### `content` Object

| Field             | Type               | Required | Description                                                                                                                                             |
| ----------------- | ------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `text`            | `string`           | Yes      | The text content of the post.                                                                                                                           |
| `mediaUrls`       | `array of strings` | Yes      | Array of media URLs. Pass any publicly accessible URL -- no upload step required. Pass `[]` for text-only posts.                                        |
| `platform`        | `string`           | Yes      | Must match `target.targetType`. Values: `twitter`, `linkedin`, `facebook`, `instagram`, `pinterest`, `tiktok`, `threads`, `bluesky`, `youtube`, `other` |
| `additionalPosts` | `array`            | No       | Additional posts for threads (Twitter, Bluesky, Threads). Each has `text` and `mediaUrls`.                                                              |

#### `target` Object

The `target` object requires `targetType` and platform-specific fields. Set `targetType` to match `content.platform`.

**Quick Reference: Required Fields Per Platform**

| Platform  | `targetType`  | Required Fields                                                                                                          | Optional Fields                                                                               |
| --------- | ------------- | ------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- |
| Twitter   | `"twitter"`   | (none)                                                                                                                   | (none)                                                                                        |
| LinkedIn  | `"linkedin"`  | (none)                                                                                                                   | `pageId`                                                                                      |
| Facebook  | `"facebook"`  | `pageId`                                                                                                                 | `mediaType`, `link`                                                                           |
| Instagram | `"instagram"` | (none)                                                                                                                   | `mediaType`, `altText`, `collaborators`, `coverImageUrl`, `shareToFeed`, `audioName`, `trial` |
| TikTok    | `"tiktok"`    | `privacyLevel`, `disabledComments`, `disabledDuet`, `disabledStitch`, `isBrandedContent`, `isYourBrand`, `isAiGenerated` | `title`, `autoAddMusic`, `isDraft`, `imageCoverIndex`, `videoCoverTimestamp`                  |
| Pinterest | `"pinterest"` | `boardId`                                                                                                                | `title`, `altText`, `link`                                                                    |
| Threads   | `"threads"`   | (none)                                                                                                                   | `replyControl`                                                                                |
| Bluesky   | `"bluesky"`   | (none)                                                                                                                   | (none)                                                                                        |
| YouTube   | `"youtube"`   | `title`, `privacyStatus`, `shouldNotifySubscribers`                                                                      | `isMadeForKids`, `containsSyntheticMedia`, `playlistIds`, `thumbnailUrl`                      |
| Webhook   | `"webhook"`   | `url`                                                                                                                    | (none)                                                                                        |

***

**Twitter**

| Field        | Type        | Required |
| ------------ | ----------- | -------- |
| `targetType` | `"twitter"` | Yes      |

**LinkedIn**

| Field        | Type         | Required | Description                                                                  |
| ------------ | ------------ | -------- | ---------------------------------------------------------------------------- |
| `targetType` | `"linkedin"` | Yes      |                                                                              |
| `pageId`     | `string`     | No       | LinkedIn Company Page ID from subaccounts. Omit to post to personal profile. |

**Carousels:** Pass 2-10 image URLs (JPG, PNG) in `content.mediaUrls`. Contouron auto-builds a LinkedIn Document carousel (LinkedIn's modern PDF-based carousel format — viewers swipe through pages). Videos cannot be mixed into a carousel.

**Facebook**

| Field        | Type         | Required | Description                                                       |
| ------------ | ------------ | -------- | ----------------------------------------------------------------- |
| `targetType` | `"facebook"` | Yes      |                                                                   |
| `pageId`     | `string`     | Yes      | Facebook Page ID from subaccounts.                                |
| `mediaType`  | `string`     | No       | `photo`, `video`, or `link`. Auto-detected from media if omitted. |
| `link`       | `string`     | No       | URL for link posts.                                               |

**Instagram**

| Field           | Type               | Required | Description                                                                   |
| --------------- | ------------------ | -------- | ----------------------------------------------------------------------------- |
| `targetType`    | `"instagram"`      | Yes      |                                                                               |
| `mediaType`     | `string`           | No       | `photo`, `video`, `carousel`, or `reel`. Auto-detected from media if omitted. |
| `altText`       | `array of strings` | No       | Alt text for each image in a carousel. Must match the number of images.       |
| `collaborators` | `array of strings` | No       | Instagram usernames to invite as collaborators.                               |
| `coverImageUrl` | `string`           | No       | Cover image URL for reels.                                                    |
| `shareToFeed`   | `boolean`          | No       | Share reel to main feed. Default: `true`.                                     |
| `audioName`     | `string`           | No       | Audio name for reels.                                                         |
| `trial`         | `boolean`          | No       | Post as a trial reel.                                                         |

**TikTok**

| Field                 | Type       | Required | Description                                                                               |
| --------------------- | ---------- | -------- | ----------------------------------------------------------------------------------------- |
| `targetType`          | `"tiktok"` | Yes      |                                                                                           |
| `privacyLevel`        | `string`   | Yes      | `PUBLIC_TO_EVERYONE`, `MUTUAL_FOLLOW_FRIENDS`, `FOLLOWER_OF_CREATOR`, or `SELF_ONLY`      |
| `disabledComments`    | `boolean`  | Yes      |                                                                                           |
| `disabledDuet`        | `boolean`  | Yes      |                                                                                           |
| `disabledStitch`      | `boolean`  | Yes      |                                                                                           |
| `isBrandedContent`    | `boolean`  | Yes      | Set to `true` for sponsored/branded content.                                              |
| `isYourBrand`         | `boolean`  | Yes      | Set to `true` to promote your own brand.                                                  |
| `isAiGenerated`       | `boolean`  | Yes      | Set to `true` for AI-generated content.                                                   |
| `title`               | `string`   | No       | TikTok post title.                                                                        |
| `autoAddMusic`        | `boolean`  | No       | Add music to photo posts. No effect on videos. Default: `false`.                          |
| `isDraft`             | `boolean`  | No       | Post as a draft. Drafts appear in TikTok mobile app notifications, not the Drafts folder. |
| `imageCoverIndex`     | `number`   | No       | Index (starting from 0) of image to use as cover for carousels.                           |
| `videoCoverTimestamp` | `number`   | No       | Timestamp in milliseconds to use as video cover.                                          |

For organic content that is not sponsored and not AI-generated, set `isBrandedContent`, `isYourBrand`, and `isAiGenerated` to `false`. Set `isYourBrand` to `true` only to promote your own brand, and `isAiGenerated` to `true` only for AI-generated content. Each field maps to a separate TikTok content disclosure, so set only the ones that apply.

**Pinterest**

| Field        | Type          | Required | Description                                         |
| ------------ | ------------- | -------- | --------------------------------------------------- |
| `targetType` | `"pinterest"` | Yes      |                                                     |
| `boardId`    | `string`      | Yes      | Pinterest Board ID. Get from List Pinterest Boards. |
| `title`      | `string`      | No       | Pin title.                                          |
| `altText`    | `string`      | No       | Pin alt text.                                       |
| `link`       | `string`      | No       | Pin URL link.                                       |

Pinterest "description" comes from the `content.text` field.

**Threads**

| Field          | Type        | Required | Description                                            |
| -------------- | ----------- | -------- | ------------------------------------------------------ |
| `targetType`   | `"threads"` | Yes      |                                                        |
| `replyControl` | `string`    | No       | `everyone`, `accounts_you_follow`, or `mentioned_only` |

**Bluesky**

| Field        | Type        | Required |
| ------------ | ----------- | -------- |
| `targetType` | `"bluesky"` | Yes      |

**YouTube**

| Field                     | Type               | Required | Description                                                                                                                          |
| ------------------------- | ------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `targetType`              | `"youtube"`        | Yes      |                                                                                                                                      |
| `title`                   | `string`           | Yes      | Video title.                                                                                                                         |
| `privacyStatus`           | `string`           | Yes      | `private`, `public`, or `unlisted`                                                                                                   |
| `shouldNotifySubscribers` | `boolean`          | Yes      |                                                                                                                                      |
| `isMadeForKids`           | `boolean`          | No       | Default: `false`                                                                                                                     |
| `containsSyntheticMedia`  | `boolean`          | No       | Whether media contains AI-generated content.                                                                                         |
| `playlistIds`             | `array of strings` | No       | YouTube playlist IDs to add the video to. Get from subaccounts.                                                                      |
| `thumbnailUrl`            | `string`           | No       | Publicly accessible image URL to use as the video thumbnail. Requires a verified YouTube account with custom thumbnail capabilities. |

YouTube "description" comes from the `content.text` field. Tags are not supported -- YouTube recommends against relying on tags for discovery ([source](https://support.google.com/youtube/answer/146402?hl=en)).

**Webhook**

| Field        | Type        | Required | Description                            |
| ------------ | ----------- | -------- | -------------------------------------- |
| `targetType` | `"webhook"` | Yes      |                                        |
| `url`        | `string`    | Yes      | The webhook URL to send the post data. |

***

#### Response

**Status Code:** `201 Created`

```json
{
  "postSubmissionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
```

Use `postSubmissionId` to poll Get Post Status for publishing progress.

Failed posts are visible at <https://my.contouron.com/failed>. The most common cause of failed posts is incorrect JSON structure.

***

#### Examples

**1. Simplest Post (Twitter, text only)**

```json
POST https://backend.contouron.com/v2/posts HTTP/1.1
Content-Type: application/json
contouron-api-key: YOUR_API_KEY

{
  "post": {
    "accountId": "98432",
    "content": {
      "text": "Hello, world!",
      "mediaUrls": [],
      "platform": "twitter"
    },
    "target": {
      "targetType": "twitter"
    }
  }
}
```

**2. Instagram Post with Images**

```json
POST https://backend.contouron.com/v2/posts HTTP/1.1
Content-Type: application/json
contouron-api-key: YOUR_API_KEY

{
  "post": {
    "accountId": "98434",
    "content": {
      "text": "Check out these photos!",
      "mediaUrls": [
        "https://example.com/image1.jpg",
        "https://example.com/image2.jpg"
      ],
      "platform": "instagram"
    },
    "target": {
      "targetType": "instagram"
    }
  }
}
```

Posting multiple images to Instagram creates a carousel.

**3. Facebook Page Post**

```json
POST https://backend.contouron.com/v2/posts HTTP/1.1
Content-Type: application/json
contouron-api-key: YOUR_API_KEY

{
  "post": {
    "accountId": "98433",
    "content": {
      "text": "New product announcement!",
      "mediaUrls": ["https://example.com/product.jpg"],
      "platform": "facebook"
    },
    "target": {
      "targetType": "facebook",
      "pageId": "123456789"
    }
  }
}
```

Get `accountId` and `pageId` from the Accounts endpoints.

**4. TikTok Post (all required fields)**

```json
POST https://backend.contouron.com/v2/posts HTTP/1.1
Content-Type: application/json
contouron-api-key: YOUR_API_KEY

{
  "post": {
    "accountId": "98435",
    "content": {
      "text": "Tips for productivity",
      "mediaUrls": ["https://example.com/video.mp4"],
      "platform": "tiktok"
    },
    "target": {
      "targetType": "tiktok",
      "privacyLevel": "PUBLIC_TO_EVERYONE",
      "disabledComments": false,
      "disabledDuet": false,
      "disabledStitch": false,
      "isBrandedContent": false,
      "isYourBrand": false,
      "isAiGenerated": true
    }
  }
}
```

**5. Scheduled Post**

```json
POST https://backend.contouron.com/v2/posts HTTP/1.1
Content-Type: application/json
contouron-api-key: YOUR_API_KEY

{
  "post": {
    "accountId": "98432",
    "content": {
      "text": "This will go live later",
      "mediaUrls": [],
      "platform": "twitter"
    },
    "target": {
      "targetType": "twitter"
    }
  },
  "scheduledTime": "2025-12-25T15:00:00Z"
}
```

**6. Twitter Thread**

```json
POST https://backend.contouron.com/v2/posts HTTP/1.1
Content-Type: application/json
contouron-api-key: YOUR_API_KEY

{
  "post": {
    "accountId": "98432",
    "content": {
      "text": "Here is a thread about AI content creation (1/3)",
      "mediaUrls": [],
      "platform": "twitter",
      "additionalPosts": [
        {
          "text": "First, research your topic using reliable sources (2/3)",
          "mediaUrls": []
        },
        {
          "text": "Then, create visuals and publish across platforms (3/3)",
          "mediaUrls": []
        }
      ]
    },
    "target": {
      "targetType": "twitter"
    }
  }
}
```

Threads work for Twitter, Bluesky, and Threads.

**7. Schedule at Next Free Slot**

```json
POST https://backend.contouron.com/v2/posts HTTP/1.1
Content-Type: application/json
contouron-api-key: YOUR_API_KEY

{
  "post": {
    "accountId": "98432",
    "content": {
      "text": "Scheduled to the next free slot",
      "mediaUrls": [],
      "platform": "twitter"
    },
    "target": {
      "targetType": "twitter"
    }
  },
  "useNextFreeSlot": true
}
```

`useNextFreeSlot` and `scheduledTime` are top-level fields, not inside `post`.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://help.contouron.com/api/post.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
