---
title: "Bulk upload posts from CSV"
method: POST
path: "/v1/posts/bulk-upload"
tags: ["Posts"]
---

# Bulk upload posts from CSV

`POST /v1/posts/bulk-upload`

## Request

- Base URL: `https://api.postzen.dev`
- URL: `https://api.postzen.dev/v1/posts/bulk-upload`
- Auth: HTTP bearer

Validates and creates up to 500 posts from a CSV file. This endpoint requires a read-write API key. Each data row targets every connected account for the selected platforms on one profile. Set `dryRun=true` to validate without checking the Free plan's monthly post allowance, ingesting media, or writing data. A non-dry-run upload is rejected with HTTP 402 before creating any rows if its publishable targets would exceed that allowance. A mixed success/failure response uses HTTP 207; all-success and all-failure responses use HTTP 200.

| CSV column | Purpose |
| --- | --- |
| `post_content` | Required base post text. |
| `platforms` | Required comma-separated platforms: `instagram`, `facebook`, `threads`, `tiktok`, `linkedin`, `x`, `youtube`, `pinterest`, `bluesky`, or `telegram`; `twitter` aliases `x`. |
| `profiles` | Required single profile id or unique profile name. |
| `schedule_time` | Required column. Use `YYYY-MM-DD HH:mm[:ss]` in `tz`, or ISO 8601 with an explicit offset. May be empty for draft, publish-now, or queue rows. |
| `tz` | IANA timezone; defaults to `UTC`. |
| `media_urls` | Comma-separated HTTP(S) URLs, up to 10 per row and 50 distinct URLs per upload. |
| `is_draft`, `publish_now`, `use_queue` | Mutually exclusive boolean mode flags. With none set, the row is scheduled. |
| `title`, `tags`, `hashtags`, `mentions`, `visibility` | General title, comma-separated tags, appended hashtags/mentions, and YouTube visibility. |
| `custom_content_<platform>` | Platform-specific content override; `custom_content_twitter` targets X. |
| `youtube_title`, `youtube_description` | YouTube title and description override. |
| `facebook_first_comment`, `linkedin_first_comment` | First comments. |
| `instagram_content_type`, `instagram_collaborators`, `instagram_first_comment` | Instagram post type, collaborators, and first comment. |
| `tiktok_privacy`, `tiktok_allow_comments`, `tiktok_allow_duet`, `tiktok_allow_stitch`, `tiktok_brand_partner`, `tiktok_organic_brand`, `tiktok_draft`, `tiktok_description` | TikTok publishing options. |
| `telegram_parse_mode`, `telegram_disable_web_page_preview`, `telegram_disable_notification`, `telegram_protect_content` | Telegram publishing options. |
| `pinterest_title`, `pinterest_link`, `pinterest_board_id`, `pinterest_cover_image_url`, `pinterest_cover_image_key_frame_time` | Pinterest pin options, including alternative video cover selections. |

## Query parameters

- `dryRun` boolean

## Headers

- `x-request-id` string

## Response `200`

Every row succeeded, or every row failed validation.

- BulkUploadResult
  - `total` integer, required
  - `valid` integer, required
  - `invalid` integer, required
  - `results` union[], required
    - union
      - object
        - `rowIndex` integer, required
        - `ok` true, required
        - `createdPostId` string: Present when the row was created by this request or replayed from a previous request with the same idempotency inputs. On dry-run, only replayed rows include this field.
      - object
        - `rowIndex` integer, required
        - `ok` false, required
        - `errors` string[], required
  - `warnings` string[], required

## Other responses

- `207`: The upload contains both successful and failed rows.
- `400`: Invalid request.
- `401`: Missing or invalid API key.
- `402`: A plan limit, missing payment method, or paused account prevents the requested operation.
- `403`: The API key does not have sufficient permission or profile access.
- `429`: Rate limit exceeded. Retry after the interval indicated by the `Retry-After` header.

---

[API](https://skmtc.dev/postzen/apis/postzen-public-api.md) · [All operations](https://skmtc.dev/postzen/apis/postzen-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/postzen/apis/postzen-public-api/revisions/40863e3710ec?raw)
