# Publish and schedule posts

> Page: https://docs.flung.dev/posting. Index of every page: https://docs.flung.dev/llms.txt

Post to one account or many at once, now or at a set time, and see what happened on each.

## TL;DR

| Question | Answer |
|---|---|
| How do I post? | `POST /v1/posts` with the text and the `accountIds`. |
| How do I schedule? | Add `publishAt`, an ISO 8601 time. Leave it out to publish now. |
| Can the text differ per platform? | Yes: `platformOverrides` sets a platform's own text and options. |
| What if a platform fails? | The post is `partially_published` or `failed`, with a reason per account. Retrying publishes only where it failed. |
| Can I change a scheduled post? | Yes, until it starts publishing; or cancel it. |

## Publish

**curl**

```bash
curl -X POST 'https://api.flung.dev/v1/posts' \
  --header "Authorization: Bearer $FLUNG_API_KEY" \
  --header 'Content-Type: application/json' \
  --header "Idempotency-Key: $(uuidgen)" \
  --data '{
  "content": "Launching today.",
  "accountIds": [
    "acct_aaaaaaaaaaaaaaaaaaaaaaaa"
  ],
  "platformOverrides": {
    "x": {
      "content": "Launching today. #launch"
    }
  },
  "variables": {
    "product": "Flung"
  }
}'
```

**TypeScript**

```ts
import { Flung } from '@flung.dev/sdk'

const flung = new Flung({ apiKey: process.env.FLUNG_API_KEY! })
const result = await flung.posts.create({
  content: 'Launching today.',
  accountIds: [
    'acct_aaaaaaaaaaaaaaaaaaaaaaaa',
  ],
  platformOverrides: {
    x: {
      content: 'Launching today. #launch',
    },
  },
  variables: {
    product: 'Flung',
  },
})
```

**fetch**

```js
const response = await fetch('https://api.flung.dev/v1/posts', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.FLUNG_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
  body: JSON.stringify({
    content: 'Launching today.',
    accountIds: [
      'acct_aaaaaaaaaaaaaaaaaaaaaaaa',
    ],
    platformOverrides: {
      x: {
        content: 'Launching today. #launch',
      },
    },
    variables: {
      product: 'Flung',
    },
  }),
})
if (!response.ok) throw new Error((await response.json()).error.message)
const result = await response.json()
```

Every POST carries an `Idempotency-Key`. Send the same key when you retry, and you get the first answer back instead of a second post. The SDK does this by itself.

## What happens next

Each account the post goes to is a target. A target is `pending` until its time, then `publishing`, then `published` with the platform's link, or `failed` with the reason. The post's own status sums them up: `published`, `partially_published` or `failed`.

Read the post again with [Get a post](https://docs.flung.dev/reference/api/get-v1-posts-id.md), or listen for `post.published` and `post.failed` with [webhooks](https://docs.flung.dev/webhooks.md).

## Platforms

Flung posts to these platforms:

`x`, `instagram`, `facebook`, `threads`, `linkedin`, `tiktok`, `youtube`, `pinterest`, `bluesky`, `mastodon`, `discord`, `farcaster`

Each platform has its own limits on text, images and video; [List platforms](https://docs.flung.dev/reference/api/get-v1-platforms.md) gives them, and a post a platform cannot carry is refused when you create it, not when it fails to publish.

## When to post

[Suggest posting times](https://docs.flung.dev/reference/api/get-v1-posting-times.md) gives the next times a platform's audience is usually most active, ready to pass as `publishAt`.

## Templates, variables and feeds

Save a post you send often as a template and schedule it again with one call. `{{name}}` placeholders in any post are filled from the workspace's variables, and an RSS or Atom feed can post each new item for you. See the Templates, Variables and Feeds sections of the [API reference](https://docs.flung.dev/reference/api.md).
