Skip to content
postpeg

Posting API

A social media posting API for ten networks

Publish text, images and video to X, Instagram, Facebook, LinkedIn, TikTok, YouTube, Threads, Pinterest, Bluesky and Google Business with one request. postpeg checks the post against each network, publishes it through their official APIs, and reports back per account, so your product gets one integration instead of ten.

How a post goes out

  1. Connect accounts. Your users approve access on each network’s own screen through a hosted OAuth link (Bluesky uses an app password). You get back an account id; postpeg keeps the tokens.
  2. Send one request. POST /v1/posts with up to 50 account_ids on any mix of networks, the content, up to 20 media items by public https URL, and any platform_options a network needs.
  3. It’s checked first. Every network’s rules run before anything is stored or sent. If one account’s network would refuse the post, nothing is published anywhere, and the 400 lists every problem at once.
  4. Each account is published separately. Each one is a target with its own status, url and error, so one network having a bad minute never holds up the rest.

Read the result with GET /v1/posts/{id}: the post is published when every target is live, or partially_published when some failed, with the reason on each failed target.

Every network’s rules, before sending

Text limits run from 280 characters on X to 63,206 on Facebook, counted as people see characters (an emoji is one). Media is required on Instagram, TikTok, YouTube and Pinterest; TikTok and YouTube take video only. YouTube needs a title and Pinterest a board_id in platform_options.

You don’t have to keep track of any of that. Send the post and postpeg answers with the exact field to fix, like content being over X’s limit or media missing a video for TikTok. The platform reference has every number, generated from the same definitions the API validates against.

When something goes wrong

A network that times out, rate-limits or has an outage is retried: up to 5 attempts, waiting 2, 4, 8 and 16 minutes, or longer if the network asks. A refusal that won’t change on retry fails at once, with the network’s reason in error.

If a publish is interrupted after the request may have reached the network, the target is marked failed rather than retried: a duplicate post is worse than a missing one. For the same reason, send an Idempotency-Key header, and a retry on your side returns the original post instead of creating a second.

When a network expires a login, the account turns reconnect_required and you can send its owner a new connect link.

Example: publish now to three networks

Leave out scheduled_at and the post is queued straight away. The response comes back before the networks answer, with each target queued.

curl https://api.postpeg.com/v1/posts \
  -H "Authorization: Bearer $POSTPEG_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: changelog-2026-10-01" \
  -d '{
    "account_ids": [
      "acc_mfz1x0k27d4q8vbn3c5s0a1p9e",
      "acc_mfz1y4r9h2c6t0wqk8e3m7ld5f",
      "acc_mfz20b5n1s8f4j7xv2p9r6hu1c"
    ],
    "content": "Scheduled posts now retry on their own when a network has a bad minute. Changelog: https://example.com/changelog #buildinpublic",
    "media": [
      {
        "url": "https://example.com/changelog.png",
        "type": "image"
      }
    ]
  }'
Response · 201 Created
{
  "id": "post_mfz2k3v8q1w5e9r4t7y0u2i6o3",
  "content": "Scheduled posts now retry on their own when a network has a bad minute. Changelog: https://example.com/changelog #buildinpublic",
  "media": [
    {
      "url": "https://example.com/changelog.png",
      "type": "image"
    }
  ],
  "platform_options": {},
  "status": "publishing",
  "scheduled_at": null,
  "targets": [
    {
      "account_id": "acc_mfz1x0k27d4q8vbn3c5s0a1p9e",
      "platform": "x",
      "status": "queued",
      "platform_post_id": null,
      "url": null,
      "error": null,
      "attempts": 0,
      "published_at": null
    },
    {
      "account_id": "acc_mfz1y4r9h2c6t0wqk8e3m7ld5f",
      "platform": "linkedin",
      "status": "queued",
      "platform_post_id": null,
      "url": null,
      "error": null,
      "attempts": 0,
      "published_at": null
    },
    {
      "account_id": "acc_mfz20b5n1s8f4j7xv2p9r6hu1c",
      "platform": "instagram",
      "status": "queued",
      "platform_post_id": null,
      "url": null,
      "error": null,
      "attempts": 0,
      "published_at": null
    }
  ],
  "created_at": "2026-09-24T14:02:11.418Z"
}

Questions

How many accounts can one post go to?
Up to 50 account_ids per request, on any mix of the ten networks. How many accounts you can connect depends on the plan: Starter $29 (10 connected accounts), Pro $79 (50 connected accounts), Scale $199 (unlimited connected accounts).
Do I handle OAuth tokens for each network?
No. Accounts connect through a hosted flow: you ask for a link, the owner approves on the network’s own screen, and postpeg keeps the tokens. Your code only deals with account ids.
What if a post publishes on some networks but not others?
The post’s status becomes partially_published. Each target keeps its own status, so the live ones have a url and the failed ones have an error saying why.
Can I call it from a script or an agent?
Yes. postpeg is a plain REST API with JSON bodies and a bearer key, so it works from any HTTP client or agent that can call a REST API.

The rest of the API

Send your first post in a few minutes

The 7-day trial has every feature and 3 connected accounts, with no card. The quickstart takes you from a key to a published post.