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

# Bài đăng

> Xuất bản văn bản, ảnh hoặc video lên nhiều nền tảng chỉ trong một request.

Một **bài đăng** xuất bản nội dung lên một hoặc nhiều nền tảng được kết nối với Profile. Bạn gửi một request, MADIAD Hub phân phối nội dung đến từng nền tảng bạn liệt kê và trả về kết quả theo từng nền tảng.

<Note>
  **Đăng bài không giới hạn trên mọi gói trả phí**, không có hạn mức số bài đăng hằng tháng. Mức sử dụng vẫn được ghi nhận, và **mỗi request được tính là một lượt đăng bất kể nhắm tới bao nhiêu nền tảng**: đăng lên TikTok, Instagram và Facebook trong một lần gọi được ghi nhận **1** lượt đăng, không phải 3. Xem [Mức sử dụng](/vi/concepts/usage) để đọc số liệu hiện tại.
</Note>

## Chọn endpoint theo loại media

| Endpoint                | Dùng cho                                  |
| ----------------------- | ----------------------------------------- |
| `POST /v1/posts/text`   | Cập nhật chỉ có văn bản                   |
| `POST /v1/posts/photos` | Một hoặc nhiều ảnh (bao gồm carousel ảnh) |
| `POST /v1/posts/video`  | Một video duy nhất                        |

Endpoint ảnh dùng `multipart/form-data` khi tải file lên, hoặc JSON thuần khi ảnh đến từ URL (`photo_urls[]`, xem [Đăng ảnh bằng URL](#đăng-ảnh-bằng-url)). Văn bản và video dùng JSON.

## Số ảnh mỗi bài

MADIAD Hub không tự đặt giới hạn số ảnh bạn đính kèm vào `photos[]`, ảnh được chuyển thẳng qua nền tảng. Mỗi nền tảng tự áp giới hạn tối đa riêng, nên giới hạn thực tế cho một bài fan-out là giới hạn **nhỏ nhất** trong số các nền tảng bạn nhắm tới:

| Nền tảng                           | Số ảnh tối đa                                        | Khi vượt giới hạn                                                                                                                             |
| ---------------------------------- | ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| Pinterest                          | 5                                                    | Giới hạn cứng, nền tảng từ chối bài đăng                                                                                                      |
| Instagram                          | 10                                                   | Giới hạn cứng, nền tảng từ chối bài đăng                                                                                                      |
| Telegram                           | 10                                                   | Giới hạn cứng, nền tảng từ chối bài đăng                                                                                                      |
| Discord                            | 10                                                   | Giới hạn cứng, nền tảng từ chối bài đăng                                                                                                      |
| X                                  | 4 mỗi tweet                                          | Ảnh dư được tự động phân bổ vào một thread, xem `x_thread_image_layout` trong [Tùy chọn theo nền tảng](/vi/concepts/platform-options)         |
| Threads                            | 10 mỗi post                                          | Media dư được tự động phân bổ vào một thread, xem `threads_thread_media_layout` trong [Tùy chọn theo nền tảng](/vi/concepts/platform-options) |
| Bluesky                            | 4                                                    | Giới hạn cứng, nền tảng từ chối bài đăng                                                                                                      |
| TikTok, LinkedIn, Facebook, Reddit | Không có giới hạn cố định do dịch vụ xuất bản áp đặt | Không áp dụng                                                                                                                                 |

<Note>
  Đây là giới hạn do chính các nền tảng công bố, không phải giới hạn MADIAD Hub áp đặt, các con số này có thể thay đổi phía nền tảng mà không báo trước. Nếu chưa chắc, hãy thử với một batch nhỏ trước.
</Note>

## Phân phối với `platforms[]`

Liệt kê tất cả nền tảng đích. Nội dung giống nhau được gửi đến từng nền tảng, trừ khi bạn ghi đè theo từng nền tảng.

```bash theme={null}
curl -X POST https://api.madiad.com/v1/posts/photos \
  -H "Authorization: Bearer $MADIAD_API_KEY" \
  -H "Idempotency-Key: 9f1c2e7a-4b6d-4e2a-9c10-7b3f8d5a1e22" \
  -F "profile_id=prof_01HZX9F2K4M7N6QR8T0V2W4Y6Z" \
  -F "platforms[]=instagram" \
  -F "platforms[]=facebook" \
  -F "platforms[]=tiktok" \
  -F "caption=New blend dropping today" \
  -F "photos[]=@./launch.jpg"
```

<Note>
  **Một request dùng chung phần media cho tất cả nền tảng được liệt kê.** Bạn có thể ghi đè phần
  chữ theo từng nền tảng (`caption` → `<platform>_caption`, xem bên dưới) và truyền tuỳ chọn riêng
  của nền tảng, nhưng `photos[]` / `photo_urls[]` / `video` bạn đính kèm sẽ đi tới **mọi** nền tảng trong request đó,
  **không có** field media riêng cho từng nền tảng. Muốn đăng **ảnh hoặc video khác nhau cho mỗi nền
  tảng**, hãy gửi **một request riêng cho từng nền tảng** (mỗi request kèm `photos[]`/`video` của
  riêng nó).
</Note>

## Đăng ảnh bằng URL

Thay vì tải file lên, bạn có thể truyền link công khai qua `photo_urls[]`. MADIAD Hub sẽ tự tải từng ảnh về phía máy chủ và đăng y hệt như khi bạn gửi file trực tiếp. Nên dùng cách này cho **ảnh dung lượng lớn hoặc nhiều ảnh một lúc**: phần truyền tải nặng diễn ra ở phía chúng tôi, request của bạn luôn gọn nhẹ và không bao giờ gặp lỗi vượt kích thước request.

```bash theme={null}
curl -X POST https://api.madiad.com/v1/posts/photos \
  -H "Authorization: Bearer $MADIAD_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 3ab77c14-08e5-4d69-b2f1-6c5904ad7e83" \
  -d '{
    "profile_id": "prof_01HZX9F2K4M7N6QR8T0V2W4Y6Z",
    "platforms": ["instagram", "facebook"],
    "caption": "New blend dropping today",
    "photo_urls": [
      "https://cdn.example.com/launch-1.jpg",
      "https://cdn.example.com/launch-2.jpg"
    ]
  }'
```

* Mỗi URL phải là **link ảnh trực tiếp, công khai, dùng `https://`** (hostname, không dùng địa chỉ IP). Link trang chia sẻ mở ra một trang web (ví dụ trang xem của drive) sẽ bị từ chối kèm thông báo lỗi rõ ràng. Hãy dùng URL file trực tiếp. Redirect được theo tối đa 5 bước, nhưng mọi bước đều phải là `https://`.
* Tối đa **40 URL mỗi request**, **30 MB mỗi ảnh** và **tổng 120 MB**.
* Cũng dùng được trong multipart: gửi `photo_urls[]` dưới dạng field text, và trộn thoải mái với `photos[]` dạng file trong cùng một request. Với carousel, file tải lên đứng trước, rồi tới ảnh từ URL, mỗi nhóm theo thứ tự gửi.

## Ghi đè theo từng nền tảng

`caption` là chú thích chung mặc định. Ghi đè cho một nền tảng cụ thể bằng field `<platform>_caption`, tiện lợi cho hashtag, mention hoặc giới hạn độ dài.

```bash theme={null}
  -F "caption=New blend dropping today" \
  -F "instagram_caption=New blend dropping today ☕ #specialtycoffee" \
  -F "x_caption=New blend out now →"
```

Cùng kiểu tiền tố này áp dụng cho các tùy chọn theo nền tảng khác, chẳng hạn `instagram_first_comment`.

<Note>
  **Ghi đè cho Instagram được đăng thành một job riêng.** Khi `instagram_caption` khác với
  `caption` chung và request còn nhắm tới nền tảng khác, MADIAD Hub gửi Instagram tách riêng để
  nó nhận đúng nội dung bạn viết. Với bài đăng thường, bạn không thấy gì khác biệt: vẫn **một
  lượt đăng** tính vào hạn mức, một `request_id`, một trạng thái để theo dõi. Với bài **hẹn
  giờ** thì có một điểm nhìn thấy được: danh sách lịch đăng hiển thị Instagram thành một mục
  riêng, nên huỷ hoặc sửa nó là thao tác tách khỏi các nền tảng còn lại.

  Có một tổ hợp bị từ chối: `add_to_queue` đi kèm `instagram_caption` khác với `caption` chung.
  Khi đó Instagram sẽ chiếm một slot hàng đợi riêng và lên vào thời điểm khác với phần còn lại,
  nên request bị từ chối thay vì đăng lệch giờ. Hãy đưa Instagram vào hàng đợi bằng một request
  riêng, hoặc dùng `caption` chung.
</Note>

## Giới hạn ký tự

`caption` ánh xạ vào trường văn bản chính của mỗi nền tảng. Giới hạn khác nhau theo nền tảng, và ở một vài nền tảng trường đó là **tiêu đề** ngắn, còn nội dung dài nằm ở `description` riêng:

| Nền tảng        | Giới hạn `caption`                       | Ghi chú                                                                          |
| --------------- | ---------------------------------------- | -------------------------------------------------------------------------------- |
| Facebook        | 63.206                                   |                                                                                  |
| Instagram       | 2.200                                    |                                                                                  |
| LinkedIn        | 3.000                                    |                                                                                  |
| TikTok (video)  | 2.200                                    |                                                                                  |
| TikTok (ảnh)    | 90                                       | Đây là **tiêu đề**, nội dung dài để ở `tiktok_description` (≤ 4.000)             |
| YouTube         | 100                                      | `caption` trở thành **tiêu đề** video; nội dung dài dùng `description` (≤ 5.000) |
| Pinterest       | 500                                      | Tiêu đề pin giới hạn 100 (`pinterest_title`)                                     |
| Reddit          | 300                                      | `caption` trở thành **tiêu đề** bài; phần thân dùng `description` (≤ 5.000)      |
| X               | 280                                      | Văn bản dài hơn sẽ tự tách thành chuỗi (thread)                                  |
| Threads         | 500                                      | Văn bản dài hơn sẽ tự tách thành chuỗi                                           |
| Bluesky         | 300                                      | Văn bản dài hơn sẽ tự tách thành chuỗi                                           |
| Google Business | 1.500                                    |                                                                                  |
| Telegram        | 4.096 (text) · 1.024 (caption kèm media) | Dài hơn sẽ bị cắt                                                                |
| Discord         | 2.000                                    | Dài hơn sẽ bị cắt                                                                |

Một số quy tắc rút ra từ bảng trên:

* **Đăng nhiều nền tảng cùng lúc?** `caption` chỉ bị từ chối ngay khi nó dài hơn giới hạn của *mọi* nền tảng được chọn. Nếu vừa với ít nhất một nền tảng, request vẫn chạy và mỗi nền tảng trả kết quả riêng, nên hãy đặt `<platform>_caption` cho nền tảng có giới hạn chặt hơn.
* **Phần ghi đè theo từng nền tảng cũng được kiểm tra**, với những nền tảng có giới hạn cứng: Instagram, LinkedIn, TikTok, YouTube, Reddit, Pinterest và Google Business. Một `<platform>_title` (hoặc `<platform>_caption`) vượt giới hạn (ví dụ `tiktok_title` > 90 cho bài ảnh, `reddit_title` > 300, hay `instagram_caption` > 2.200) sẽ bị báo lỗi rõ ràng trước khi đăng. X, Threads và Bluesky không kiểm trước vì chúng tự tách thành chuỗi bài thay vì từ chối; Telegram và Discord thì cắt bớt; còn ghi đè cho Facebook chỉ bị giới hạn ở Reels. Những trường hợp này được gửi thẳng tới nền tảng và tự báo kết quả riêng.
* **Link trên X.** Mọi URL mà X biến thành liên kết bấm được sẽ bị gỡ khỏi bài X trước khi đăng. Hãy để link trong hồ sơ hoặc trong ảnh/video.

## Tùy chọn nâng cao theo nền tảng

Bất kỳ tùy chọn nào một nền tảng hỗ trợ đều có thể truyền qua, MADIAD Hub chuyển tiếp nguyên vẹn, nên bạn không bị giới hạn ở các field liệt kê ở đây. Thêm tiền tố tên nền tảng khi tùy chọn đó đặc thù cho nền tảng. Một vài ví dụ phổ biến:

| Field                                               | Nền tảng  | Tác dụng                                                     |
| --------------------------------------------------- | --------- | ------------------------------------------------------------ |
| `instagram_first_comment`                           | Instagram | Tự động đăng bình luận đầu tiên sau khi xuất bản             |
| `media_type`                                        | Instagram | `REELS`, `STORIES`, …                                        |
| `privacy_level`                                     | TikTok    | `PUBLIC_TO_EVERYONE`, `SELF_ONLY`, …                         |
| `disable_comment`, `disable_duet`, `disable_stitch` | TikTok    | Công tắc tương tác                                           |
| `auto_add_music`                                    | TikTok    | Thêm nhạc nền cho bài ảnh (`true`/`false`, mặc định `false`) |
| `tags[]`                                            | YouTube   | Tags cho video                                               |
| `privacyStatus`                                     | YouTube   | `public`, `unlisted`, `private`                              |
| `visibility`                                        | LinkedIn  | Phạm vi hiển thị bài đăng                                    |
| `poll_options[]` + `poll_duration`                  | X         | Đính kèm poll                                                |

Các field dạng mảng dùng quy ước `field[]`, lặp lại key một lần cho mỗi giá trị.

Để xem toàn bộ các tùy chọn theo từng nền tảng (mức độ riêng tư, loại video, poll, CTA, tải phụ đề và nhiều hơn nữa), xem [Tùy chọn theo nền tảng](/vi/concepts/platform-options).

## Bình luận đầu tiên (first comment)

Tự động đăng một bình luận ngay khi bài vừa xuất bản, tiện để gắn link, hashtag hoặc lời kêu gọi hành động mà bạn không muốn nhét vào caption chính. Đặt `first_comment` làm giá trị chung, và ghi đè theo từng nền tảng bằng `<platform>_first_comment` (giá trị riêng từng nền tảng được ưu tiên khi có cả hai).

```bash theme={null}
  -F "caption=New blend dropping today" \
  -F "first_comment=Mua ngay tại 👉 link trong bio" \
  -F "instagram_first_comment=Bấm link trong bio ☕ #specialtycoffee"
```

Hỗ trợ trên Instagram, Facebook, Threads, Bluesky, Reddit, X, YouTube và LinkedIn. Một vài hành vi riêng theo nền tảng:

* **X và Threads**: đăng dưới dạng reply cho bài. Với bài X tự tách chuỗi, nó reply vào tweet cuối của chuỗi.
* **YouTube**: đăng thành bình luận cấp cao nhất dưới video.
* **Instagram**: chỉ áp dụng cho bài ảnh và video (Instagram không có bài chỉ văn bản).

Để đính ảnh vào bình luận, gửi `first_comment_media[]` dạng file nhị phân, y hệt `photos[]`. Hiện chỉ hỗ trợ **Reddit**, và không dùng được cho bài đã lên lịch hoặc đang trong hàng đợi.

```bash theme={null}
  -F "first_comment=Bộ ảnh chi tiết bên dưới 👇" \
  -F "first_comment_media[]=@./detail-1.jpg" \
  -F "first_comment_media[]=@./detail-2.jpg"
```

## Caption sinh bằng AI

Để MADIAD Hub tự viết caption thay vì bạn cung cấp. Hữu ích nhất với bài ảnh và video:

```bash theme={null}
  -F "autogenerate=true" \
  -F "autogenerate_language=vi"
```

| Field                      | Tác dụng                              |
| -------------------------- | ------------------------------------- |
| `autogenerate`             | Sinh cả title lẫn description         |
| `autogenerate_title`       | Chỉ sinh title                        |
| `autogenerate_description` | Chỉ sinh description                  |
| `autogenerate_language`    | Ép ngôn ngữ đầu ra (ví dụ `en`, `vi`) |

## Yêu cầu của từng nền tảng

<AccordionGroup>
  <Accordion title="Facebook đăng lên Page">
    Bài đăng Facebook đi đến một **Page**, không phải Profile cá nhân. Nếu Profile chỉ có một Page thì tự động dùng Page đó; nếu có nhiều Page, truyền `facebook_page_id` để chọn. Để liệt kê các Page của một Profile và lấy ID của chúng, dùng `GET /v1/connections/facebook/pages`, xem [Tìm ID của Page & board](/vi/concepts/profiles).
  </Accordion>

  <Accordion title="Ảnh: tải file lên hoặc truyền URL; video dùng URL">
    Gửi ảnh dưới dạng file nhị phân (`photos[]=@file`) hoặc link công khai (`photo_urls[]`), xem [Đăng ảnh bằng URL](#đăng-ảnh-bằng-url). Với video, truyền một `video_url` công khai.
  </Accordion>

  <Accordion title="Reddit cần tiêu đề">
    Bài đăng Reddit luôn có tiêu đề. Mặc định caption được dùng làm tiêu đề; truyền `reddit_title` nếu muốn đặt tiêu đề riêng.
  </Accordion>
</AccordionGroup>

## Đọc response

Lệnh đăng trả về `status` của bài, các nền tảng đã nhắm tới, và các id để bạn poll:

```json theme={null}
{
  "status": "processing",
  "profile_id": "prof_01HZX9F2K4M7N6QR8T0V2W4Y6Z",
  "platforms": ["instagram", "facebook", "tiktok"],
  "request_id": "req_01HZX9H6S8T0V2W4X6Y8Z0A2B4",
  "job_id": null,
  "results": null
}
```

* `completed`: đã xuất bản đồng bộ, `results` chứa kết quả theo từng nền tảng.
* `processing`: đang tải lên (thường gặp với video). Poll bằng `request_id`, hoặc đăng ký [webhooks](/vi/concepts/webhooks).
* `scheduled`: đã lên lịch cho thời điểm tương lai, poll bằng `job_id`.
* `partial`: một số nền tảng đã đăng thành công và ít nhất một nền tảng bị từ chối, kiểm tra từng mục trong `results`.
* `failed`: tất cả nền tảng nhắm tới đều từ chối bài đăng. Mã HTTP vẫn là `200`, lý do theo từng nền tảng nằm trong `results`.
* `unknown`: chưa xác định được kết quả trong thời gian chờ (trả về HTTP `502` với mã `upstream_timeout`). Bài có thể đã lên, **đừng** retry ngay; xem [Lỗi](/vi/concepts/errors) và [Idempotency](/vi/concepts/idempotency).

Poll trạng thái (`GET /v1/posts/status`) dùng cùng bộ giá trị này.

Khi có `results`, nó được phân theo từng nền tảng. Mỗi mục có `success`, kèm `publish_id` và `url` khi bài đã lên, hoặc `error` và `error_code` khi nền tảng từ chối:

```json theme={null}
{
  "results": {
    "instagram": { "success": true, "publish_id": "17912345678901234", "url": "https://instagram.com/p/abc123" },
    "tiktok":    { "success": false, "error": "TikTok đã nhận 15/15 bài trong 24 giờ qua…", "error_code": "daily_cap_reached" }
  }
}
```

`error_code` là mã lý do ngắn gọn dành cho máy đọc (ví dụ `account_restricted`, `daily_cap_reached`, `media_invalid_format`), hãy phân nhánh theo mã này thay vì theo câu chữ của `error`. Mã chỉ xuất hiện khi nền tảng có trả về.

Response của lệnh đăng và kết quả poll trạng thái dùng đúng cùng một cấu trúc này.

Khi một số (nhưng không phải tất cả) nền tảng thất bại, `status` cấp cao là `partial` và mảng `failed_platforms` liệt kê các nền tảng đã thất bại.

<Tip>
  Một bài đăng có thể thành công một phần, khi một nền tảng xuất bản được còn nền tảng khác thất bại. Hãy kiểm tra `results` theo từng nền tảng thay vì chỉ dựa vào `status` ở cấp cao nhất.
</Tip>

## Kiểm tra trạng thái sau

Poll một bài bất đồng bộ hoặc đã lên lịch bằng `request_id` hoặc `job_id` từ response của lệnh đăng:

```bash theme={null}
curl "https://api.madiad.com/v1/posts/status?request_id=req_01HZX9H6S8T0V2W4X6Y8Z0A2B4" \
  -H "Authorization: Bearer $MADIAD_API_KEY"
```

Để nhận cập nhật chủ động thay vì kiểm tra định kỳ, xem [Webhooks](/vi/concepts/webhooks).
