# Posts (/en/api/posts)

## Create a post [#create-a-post]

```http
POST /v1/posts
Authorization: Bearer tb_live_xxx
Idempotency-Key: 6f1c2b7e-0d8a-4f7e-9a51-2c1f7b0e9d34
Content-Type: application/json

{
  "content": "Weekend promo 🎉",
  "media_ids": ["0b9d..."],
  "targets": [{ "account_id": "a1.." }, { "account_id": "b2.." }],
  "scheduled_at": "2026-10-15T09:00:00+07:00"
}
```

| Field          | Description                                                                                                                                                                                                                               |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `content`      | The post text                                                                                                                                                                                                                             |
| `media_ids`    | Media ids from an [upload](/en/api/media), in display order                                                                                                                                                                               |
| `media_urls`   | Optional. Public URLs of photos or videos; Tebar downloads them first (same rules as `POST /v1/media/from-url`) and adds them after `media_ids`. Up to 20 with `media_ids`. A failed download makes no post (`400 media_download_failed`) |
| `targets`      | Target accounts (`account_id` from `GET /v1/accounts`)                                                                                                                                                                                    |
| `scheduled_at` | Optional. Without it, the post is published right away                                                                                                                                                                                    |

`201` response:

```json
{
  "id": "p1..",
  "status": "scheduled",
  "scheduled_at": "2026-10-15T02:00:00Z",
  "targets": [
    {
      "id": "t1..",
      "account_id": "a1..",
      "platform": "instagram",
      "status": "pending",
      "permalink": null
    },
    {
      "id": "t2..",
      "account_id": "b2..",
      "platform": "threads",
      "status": "pending",
      "permalink": null
    }
  ]
}
```

Publishing runs in the background. Check `GET /v1/posts/{id}`: each target becomes `published` with a `permalink`, or `failed` with an `error_code`.

A single video on Instagram publishes as a **Reel** automatically. Two or more media items become a carousel (Instagram up to 10, Threads up to 20).

## A version per account [#a-version-per-account]

Each target can have its own text and/or media (`media_ids` and/or `media_urls`). Fields not sent follow the shared version. `content: ""` means deliberately without text.

```json
{
  "content": "What's your favorite coffee?",
  "targets": [
    { "account_id": "th..", "options": { "poll": { "options": ["Black", "Latte"] } } },
    { "account_id": "ig..", "content": "New on the menu this week ☕", "media_ids": ["m1.."] }
  ]
}
```

## Threads threads [#threads-threads]

`content` is the first post. Each item of `options.thread` goes out as the next reply, in order (up to 10 follow-up parts). A part is text, or `{ "text", "media_ids" }` / `{ "text", "media_url" }` with 1 photo or video (`media_url` is downloaded by Tebar like `media_urls`). If publishing fails partway, a retry continues from the next part without reposting the ones already out. Needs the `threads_manage_replies` permission (see the table below).

```json
{
  "content": "5 tips for iced latte at home 🧵",
  "targets": [
    {
      "account_id": "th..",
      "options": {
        "thread": [
          "1. Start with a strong espresso.",
          { "text": "2. Cold milk, not hot.", "media_ids": ["m1.."] },
          { "media_url": "https://example.com/latte.mp4" }
        ]
      }
    }
  ],
  "scheduled_at": "2026-10-31T19:30:00+07:00"
}
```

## Options per platform [#options-per-platform]

Sent in `targets[].options`. Unknown keys are refused (`400 invalid_options`).

| Platform  | Option                                                                | Rules                                                                                                                                                                                                                                                                                                                                                                                  |
| --------- | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Threads   | `thread: (string \| { text?, media_ids? })[]`                         | **Needs the `threads_manage_replies` permission (accounts connected before Oct 24, 2026: reconnect); without it `400 option_permission_missing`.** Thread: 1–10 follow-up parts. Each part is text (≤ 500 characters) or `{ "text": "…", "media_ids": ["…"] }` with 1 photo or video. Errors in a specific part include `details.thread_part` (2 = the first part after the main post) |
| Threads   | `poll: { options: string[] }`                                         | 2–4 options, 1–25 characters. Only posts without media                                                                                                                                                                                                                                                                                                                                 |
| Threads   | `link_attachment: url`                                                | Link card. Only posts without media                                                                                                                                                                                                                                                                                                                                                    |
| Threads   | `text_attachment: { text, link_url? }`                                | Long text ≤ 10,000 characters. Only posts without media                                                                                                                                                                                                                                                                                                                                |
| Threads   | `topic_tag: string`                                                   | 1–50 characters, without `.` and `&`                                                                                                                                                                                                                                                                                                                                                   |
| Threads   | `reply_control`                                                       | `everyone`, `accounts_you_follow`, `mentioned_only`, `followers_only`, `parent_post_author_only`. Anything but `everyone` (Threads' default, not sent) needs `threads_manage_replies`                                                                                                                                                                                                  |
| Instagram | `format: "feed" \| "story"`                                           | Story: exactly 1 media item, no caption, videos 3–60 seconds and ≤ 100 MB                                                                                                                                                                                                                                                                                                              |
| Instagram | `share_to_feed: boolean`                                              | Reels only (default `true`)                                                                                                                                                                                                                                                                                                                                                            |
| Instagram | `cover_media_id` / `thumb_offset_ms`                                  | Reel cover: an image id, or a video frame in milliseconds                                                                                                                                                                                                                                                                                                                              |
| TikTok    | `privacy_level`                                                       | Business accounts (`video_public_only` in `GET /v1/accounts/{id}/tiktok/creator-info`): optional; videos are always `PUBLIC_TO_EVERYONE` (anything else is `400 tiktok_privacy_unavailable`), photos without a privacy go out public. Other accounts: **required** for direct posts, one of the `privacy_level_options`, chosen by the user (without it `400 tiktok_privacy_required`) |
| TikTok    | `post_mode: "direct" \| "draft"`                                      | `draft`: sent to the TikTok app's inbox to be finished there                                                                                                                                                                                                                                                                                                                           |
| TikTok    | `allow_comment`, `allow_duet`, `allow_stitch`                         | Business accounts: allowed by default, `false` turns off. Other accounts: default `false`. Duet and Stitch are video only. Anything the creator turned off in TikTok stays off                                                                                                                                                                                                         |
| TikTok    | `commercial: { your_brand, branded_content }`                         | Commercial content disclosure (at least one `true`)                                                                                                                                                                                                                                                                                                                                    |
| TikTok    | `video_cover_timestamp_ms`, `is_aigc`                                 | The video's cover frame in milliseconds; mark AI-generated content. Business accounts also take `cover_media_id`: a JPG/PNG image id (360-1920 px, short side up to 1080 px, 20 MB) as the cover                                                                                                                                                                                       |
| TikTok    | `photo_title`, `auto_add_music`                                       | Photos only. A TikTok post holds 1 video or 1–35 photos (`400 invalid_media_mix`)                                                                                                                                                                                                                                                                                                      |
| YouTube   | `title`, `made_for_kids`                                              | Both **required**. `title` 1-100 characters without `<` or `>`; always ask the user for `made_for_kids`. The post text is the description (up to 5,000, no `<` or `>`)                                                                                                                                                                                                                 |
| YouTube   | `privacy: "public" \| "unlisted" \| "private"`, `tags`, `category_id` | Default `public`. `tags` up to 500 characters in total                                                                                                                                                                                                                                                                                                                                 |
| YouTube   | `contains_synthetic_media`, `notify_subscribers`                      | Mark realistic AI or altered content; `notify_subscribers: false` skips notifying subscribers                                                                                                                                                                                                                                                                                          |
| YouTube   | `cover_media_id`                                                      | Id of a JPG or PNG from the media library as the thumbnail, set once the video is up. Not for Shorts. The channel must be phone-verified (youtube.com/verify); when YouTube refuses, the video stays up with its automatic thumbnail                                                                                                                                                   |
| LinkedIn  | `visibility: "PUBLIC" \| "CONNECTIONS"`                               | `PUBLIC` (default): everyone on LinkedIn. `CONNECTIONS`: connections only                                                                                                                                                                                                                                                                                                              |
| Telegram  | `silent`, `protect_content`                                           | No notification sound; the post cannot be forwarded or saved. Default `false`                                                                                                                                                                                                                                                                                                          |
| Telegram  | `no_link_preview`                                                     | Links in the text without a preview card. Only posts without media                                                                                                                                                                                                                                                                                                                     |
| Pinterest | `board_id`, `title`, `link`                                           | `board_id` **required**, from `GET /v1/accounts/{id}/pinterest/boards` (no board: `400 pinterest_board_required`). `title` up to 100 characters, `link` the destination URL. The post text is the description (up to 800). Exactly 1 photo                                                                                                                                             |
| Discord   | `silent`, `no_link_preview`                                           | No push notification to members; links in the text without a preview card. Default `false`. Mentions such as `@everyone` are always sent without pinging anyone                                                                                                                                                                                                                        |
| LinkedIn  | `link: url`                                                           | Article card. Only posts without media                                                                                                                                                                                                                                                                                                                                                 |

Threads allows 5 unique links per post (`400 too_many_links`).

## Managing posts [#managing-posts]

| Request                      | What it does                                                                                                                   |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `PATCH /v1/posts/{id}`       | Change `content`, `media_ids`, `scheduled_at`, or each account’s version and options (`targets[]`) of a post not published yet |
| `DELETE /v1/posts/{id}`      | Cancel a scheduled post                                                                                                        |
| `POST /v1/posts/{id}/retry`  | Retry the `failed` accounts. Never reposts the ones already published                                                          |
| `POST /v1/posts/{id}/remove` | Remove from Tebar's history. The post on Instagram/Threads/TikTok is not deleted                                               |

A post that has started publishing cannot be changed (`409 post_not_editable`). To publish a scheduled post now, send `PATCH` with `scheduled_at` set to the current time.

To change one account's version or options in a scheduled post, send `targets` with accounts already in the post. A field sent replaces that account's (`options` as a whole, so send again the other options you want to keep); `content` or `media_ids` set to `null` make the account follow the shared version again. Accounts cannot be added or removed (`400 account_not_in_post`).

```json
{
  "targets": [
    { "account_id": "th..", "options": { "thread": ["The new part 2"], "topic_tag": "coffee" } },
    { "account_id": "ig..", "content": null, "media_ids": null }
  ]
}
```
