OmniSocialsOmniSocials
DocumentationAPI reference
Help centerSupport
  • Documentation
  • API reference
Developers
  • Quickstart
  • API reference
  • SDKs
  • MCP server
  • CLI
For AI agents
  • Docs for AI agents
  • llms.txt
  • OpenAPI spec
  • Postman collection
Product
  • OmniSocials
  • Pricing
  • Changelog
  • Help center
Company
  • Support
  • Privacy policy
  • Terms of service

© 2026 OmniSocials

OmniSocials on GitHubOmniSocials on XOmniSocials on LinkedIn
Overview
Get started
    QuickstartAuthenticationTestingRate limits and errorsRetries and duplicates
SDKs
CLI
MCPDocs for AI agentsWebhooks
Guides
Platforms
Integrations
Migrate
Plans and billing
GlossaryChangelogAPI reference
Get started

Retries and duplicate posts: retry safely

A social post that goes out twice is worse than one that fails. This page says what OmniSocials does when a request or a publish goes wrong, and how to retry without posting twice.

The short version

  • The API has no idempotency keys. Every POST /posts/create makes a new post, even with the same body.
  • After a timeout or a 5xx on create, check GET /posts before you send the request again.
  • Retry failed channels with POST /posts/:id/retry, never by creating the post again.
  • 429 and 503 storage_unavailable did nothing, so they are safe to resend after Retry-After.
  • One post can send several webhook events. Track state per data.post_id.

No idempotency keys

The API does not read an Idempotency-Key header or anything like it, and POST /posts/create does not compare a new post with earlier ones. Two identical requests create two posts, and when both publish, both go out (unless the platform refuses the second, see Duplicate content).

Media uploads are the exception. An image or video up to 100 MB is matched by its content: uploading the same bytes to the same workspace again returns the existing media item instead of a new one. This covers POST /media/upload, upload-from-base64, presigned uploads, upload-from-url and media_urls on a post. A file over 100 MB, ingested in the background through upload-from-url, creates a new item on every call.

Timeouts and 5xx errors

POST /posts/create saves the post before it builds the response. A 500 internal_error or a dropped connection can therefore arrive after the post was saved, and a saved post with publish_now: true publishes anyway. Treat a timeout or a 5xx on create as "unknown", not as "failed".

To make the check easy, give each create a unique source value. source is a free-form label (it defaults to "api", is shown in the dashboard and comes back on every post):

TerminalTerminal
curl -X POST https://api.omnisocials.com/v1/posts/create \ -H "Authorization: Bearer $OMNISOCIALS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "content": { "default": "Spring sale starts today" }, "accounts": ["your-account-id"], "publish_now": true, "source": "spring-sale-job-8f3a" }'

If that call times out or answers 5xx:

  1. Wait a few seconds, then call GET /posts?limit=20. Posts come back newest first.
  2. Look for a post whose source is spring-sale-job-8f3a.
  3. If it is there, do not create again. Poll GET /posts/:id for its outcome.
  4. If it is not there, send the create again with the same source.

The other write endpoints are safer to repeat:

EndpointWhat a second identical call does
POST /posts/:id/publishOnly draft and scheduled posts can be published. A second call answers 400 invalid_status (the post is posting or warning), 400 already_published or 400 post_failed, and publishes nothing
POST /posts/:id/retryWhile the retry runs the post is posting, so a second call answers 400 invalid_status
DELETE /posts/:idThe second call answers 404 not_found
Media uploads up to 100 MBReturns the same media item
POST /inbox/conversations/:id/replyThe same text and attachment to the same conversation within 10 minutes answers 409 duplicate_reply. Nothing is sent again, and data carries the earlier message. Treat it as sent
Any request answered 429Rejected before it ran. Resend after Retry-After
Any upload answered 503 storage_unavailableNothing was stored. Resend after Retry-After

How OmniSocials retries a publish

Publishing runs in the background after your request returns. Several guards keep a channel from getting the same post twice:

  • One success per channel. A channel's success is recorded the moment the platform confirms it. Every later run of the same post (a retry, or recovery after a crash) skips the channels that already succeeded.
  • Lookup before resend. When Instagram's publish call or Facebook's feed post call times out or answers 5xx, OmniSocials first looks on the account for a post created after the attempt with the same caption, and keeps it when it finds one. Instagram sometimes answers "Action blocked" for a post that is already live; the same lookup runs then. A post without a caption, such as a story, cannot be matched this way.
  • Unknown outcomes are reported, not retried. When X accepts a post but returns no post id, the channel fails with "X accepted the request but did not return a post id, so we can't confirm the post went live. Check your X profile before retrying, to avoid a duplicate."
  • Threads and stories resume. A Threads thread that fails halfway resumes at the first unpublished part, and a multi-slide story publishes only the slides that did not go out.

Automatic retries

A failure that OmniSocials classifies as temporary gets an automatic retry about 15 minutes later, up to 3 automatic attempts per channel. While one is planned, the channel's message in errors ends with "We'll retry this platform automatically in about 15 minutes."

The post's status is failed or warning in the meantime. Calling POST /posts/:id/retry yourself replaces the planned automatic retry. Automatic attempts are counted apart from the 3 manual retries per channel.

warning and failed

StatusMeaningWebhook
warningPublished on some channels, failed on others. published_urls has the live links, errors the failed channelspost.published with data.status: "warning"
failedFailed on every channelpost.failed

An errors entry disappears once a retry of that channel succeeds. GET /posts?status=failed does not return warning posts, so query both when you track failures. See Post statuses.

Retrying failed channels

POST /posts/:id/retry publishes the failed channels of a failed or warning post again, on the same post. Channels that already published are never posted again.

TerminalTerminal
curl -X POST https://api.omnisocials.com/v1/posts/59546574/retry \ -H "Authorization: Bearer $OMNISOCIALS_API_KEY"
JSON
{ "data": { "id": "59546574", "status": "posting", "platforms": ["linkedin"], "message": "Retry queued for: linkedin. Platforms that already succeeded are never re-published. Poll GET /posts/{id} for the outcome." } }

The retry runs in the background. Poll GET /posts/:id until status is no longer posting.

ResponseMeaning
400 invalid_statusThe post is not failed or warning
400 nothing_to_retryNo failed channel is recorded, for example on posts from before per-channel tracking. Create a new post instead
400 max_retries_reachedA failed channel was already retried 3 times. All failed channels retry together, so one exhausted channel blocks the whole request. Create a new post

Channels dismissed with "ignore" in the dashboard are not retried. POST /posts/:id/publish refuses failed posts (400 post_failed) and warning posts (400 invalid_status); retry is the endpoint for them.

Fix the cause first. A retry sends the same post again, so it fails again when the cause is the content or the account: a duplicate, a missing permission, an expired connection. Reconnect the account, top up credits, or change the post first. Known issues lists the common causes per channel. A warning post can still be edited with PATCH /posts/:id before you retry; a failed post cannot (400 invalid_status), so create a new post when its content has to change.

Retries made in the dashboard can create a separate retry post, linked with retry_of and retries. See Retry linkage.

Duplicate content

OmniSocials does not refuse a post for being the same as an earlier one. Some platforms do:

ChannelMessage
Facebook"Facebook rejected this as a duplicate"
LinkedIn"LinkedIn rejected this post as a duplicate: identical content already exists on your profile" (or page)
X"This is a duplicate of a tweet you already posted."

These refusals also cover content that was posted outside OmniSocials. A retry with the same text fails the same way: change the text first.

Webhooks for one post can arrive more than once

Every delivery carries X-OmniSocials-Delivery, a unique id per event that stays the same when a delivery is retried. Deduplicate deliveries on it.

One post can still produce several events, each with its own delivery id:

  • post.failed after the first attempt, then post.published when a retry (manual or automatic) succeeds.
  • post.published with data.status: "warning" after the first attempt, then post.published again after each retry.
  • A planned automatic retry sends nothing until it ends.

Keep your state per data.post_id, read data.status and data.targets on every event, and order events by created_at. See Webhooks.

Checklist

SituationResend?What to do
429 rate_limit_exceededYesWait Retry-After seconds
503 storage_unavailableYesWait Retry-After seconds, send the same request
400, 401, 402, 403, 404NoFix the request, key, scope or credits first
Timeout or 5xx on POST /posts/createOnly after a checkLook for the post's source in GET /posts; create again only when it is missing
Timeout or 5xx on publish or retryYesA refusal with invalid_status, already_published or post_failed means the first call went through. Poll the post
A channel failed (warning or failed)Use retryFix the cause, then POST /posts/:id/retry
409 duplicate_replyNoThe reply was already sent

For the full status code table and the error body, see Rate limits and errors.

Last modified on October 21, 2026
Rate limits and errorsSDKs
On this page
  • The short version
  • No idempotency keys
  • Timeouts and 5xx errors
  • How OmniSocials retries a publish
    • Automatic retries
  • warning and failed
  • Retrying failed channels
  • Duplicate content
  • Webhooks for one post can arrive more than once
  • Checklist
JSON