# Publish to Social

> Publish images or videos directly to connected social accounts

- **URL**: https://orshot.com/docs/api-reference/social-publish

---

Publish content to your connected social media accounts. Use this when you already have a media URL (e.g., from a previous render) and want to post it without rendering again.

To publish as part of a render in a single call, use the [`publish` parameter](https://orshot.com/docs/publish/publish-from-api) on [Render from Studio Template](https://orshot.com/docs/api-reference/render-from-studio-template) instead.

## Endpoint

### POST /social/publish```markdown tab="Endpoint"
https://api.orshot.com/v1/social/publish
```## Request Example```js
await fetch("https://api.orshot.com/v1/social/publish", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: "Bearer <ORSHOT_API_KEY>",
  },
  body: JSON.stringify({
    accounts: [1, 2],
    content: "Check out our latest design!",
    media_url: "https://storage.orshot.com/.../image.png",
  }),
});
```Find your account IDs using the [List Social Accounts](https://orshot.com/docs/api-reference/social-accounts-list) endpoint, or from the **Social Accounts** page in your workspace sidebar.

### Schedule a Post```js
await fetch("https://api.orshot.com/v1/social/publish", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: "Bearer <ORSHOT_API_KEY>",
  },
  body: JSON.stringify({
    accounts: [1],
    content: "This will be posted later!",
    media_url: "https://storage.orshot.com/.../image.png",
    schedule: { scheduledFor: "2030-01-15T10:00:00Z" },
    timezone: "America/New_York",
  }),
});
```### Save as Draft```js
await fetch("https://api.orshot.com/v1/social/publish", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: "Bearer <ORSHOT_API_KEY>",
  },
  body: JSON.stringify({
    accounts: [1, 2],
    content: "Draft post — will publish later from the dashboard",
    media_url: "https://storage.orshot.com/.../image.png",
    isDraft: true,
  }),
});
```### Platform-Specific Options```js
await fetch("https://api.orshot.com/v1/social/publish", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: "Bearer <ORSHOT_API_KEY>",
  },
  body: JSON.stringify({
    accounts: [1, 2],
    content: "New product launch!",
    media_url: "https://storage.orshot.com/.../image.png",
    platformOptions: {
      "1": { firstComment: "Follow us for more updates!" },
      "2": { title: "Product Launch", link: "https://acme.com/launch" },
    },
  }),
});
```## Request Parameters

| Parameter                    | Type    | Required | Description                                                                          |
| ---------------------------- | ------- | -------- | ------------------------------------------------------------------------------------ |
| `accounts`                   | Array   | Yes      | Array of account IDs to publish to (see [List Social Accounts](https://orshot.com/docs/api-reference/social-accounts-list)) |
| `content`                    | String  | No       | Caption/text for the post (max 5000 characters)                                      |
| `media_url`                  | String  | No       | URL of the image or video to publish                                                 |
| `media_urls`                 | Array   | No       | Multiple media URLs for carousel posts (use instead of `media_url`)                  |
| `isDraft`                    | Boolean | No       | `true` to save as draft instead of publishing                                        |
| `schedule.scheduledFor`      | String  | No       | ISO 8601 timestamp to schedule the post (must be at least 60 seconds in the future)  |
| `timezone`                   | String  | No       | IANA timezone string for scheduling (e.g., `"America/New_York"`, `"Europe/London"`)  |
| `platformOptions`            | Object  | No       | Per-account options keyed by account ID (see below)                                  |

### Platform Options

Pass platform-specific options keyed by account ID:

| Platform  | Option              | Description                          |
| --------- | ------------------- | ------------------------------------ |
| LinkedIn  | `firstComment`      | Auto-post a first comment            |
| LinkedIn  | `disableLinkPreview` | Disable the link preview card       |
| Pinterest | `title`             | Pin title                            |
| Pinterest | `link`              | Destination URL for the pin          |

## Response Example```json
{
  "data": {
    "post_id": 42,
    "status": "published",
    "platforms": [
      {
        "platform": "twitter",
        "username": "acmehq",
        "name": "Acme HQ",
        "status": "published",
        "url": "https://twitter.com/acmehq/status/1234567890"
      },
      {
        "platform": "linkedin",
        "username": "acme-inc",
        "name": "Acme Inc",
        "status": "published",
        "url": "https://linkedin.com/feed/update/urn:li:share:1234567890"
      }
    ]
  }
}
```## Response Fields

| Field                    | Type    | Description                                                                  |
| ------------------------ | ------- | ---------------------------------------------------------------------------- |
| `post_id`                | Integer | Unique identifier for the post                                               |
| `status`                 | String  | Overall status: `published`, `scheduled`, `drafted`, `partial`, or `failed`  |
| `platforms`              | Array   | Per-account results                                                          |
| `platforms[].platform`   | String  | Platform name                                                                |
| `platforms[].username`   | String  | Account username                                                             |
| `platforms[].name`       | String  | Account display name                                                         |
| `platforms[].status`     | String  | `published`, `scheduled`, `drafted`, or `failed`                             |
| `platforms[].url`        | String  | Link to the published post (when available)                                  |
| `platforms[].error`      | String  | Error message (only on failure)                                              |

A `partial` status means some accounts succeeded and others failed — check individual `platforms[].status` for details.

## Format Compatibility

Not all formats work on every platform:

| Format           | Unsupported Platforms                    |
| ---------------- | ---------------------------------------- |
| PDF              | All platforms (not supported)            |
| MP4, WebM, GIF   | Google Business                          |
| PNG, JPG, WebP   | TikTok, YouTube (video-only platforms)   |

If some accounts are incompatible with the media format, they are skipped and returned with `status: "failed"` and a reason in the `error` field.

## Rate Limits

This endpoint is rate limited to **20 requests per minute** per workspace. Rate limit headers are included in every response:

| Header                  | Description              |
| ----------------------- | ------------------------ |
| `X-RateLimit-Limit`     | Maximum requests per minute |
| `X-RateLimit-Remaining` | Remaining requests in the current window |
| `Retry-After`           | Seconds to wait (only on `429` responses) |

## Error Responses

| Code | Description                                                |
| ---- | ---------------------------------------------------------- |
| 400  | Missing or empty `accounts` array                          |
| 400  | Content exceeds 5000 characters                            |
| 400  | Invalid `schedule.scheduledFor` timestamp                  |
| 400  | Scheduled time must be in the future                       |
| 400  | No valid connected accounts found for the given IDs        |
| 403  | Missing or invalid API key                                 |
| 403  | Social publishing requires a paid plan                     |
| 422  | No compatible platforms for the media format               |
| 429  | Rate limit exceeded                                        |