Skip to main content
Network timeouts, 5xx responses, and dropped connections leave you not knowing whether a POST /v1/social/posts landed. SmartlyQ has two independent layers so a retry is always safe.

Layer 1: idempotency keys

Send an X-Idempotency-Key header (X-Request-Id is accepted as an alias) with a fresh value per logical post - generate a UUID v4 in your code. If the call fails ambiguously (timeout, 5xx, connection reset), retry it with the same key:
  • First call creates the post and returns 201.
  • A retry with the same key returns 200 with the original post and idempotent_replay: true - nothing new is created:
Replay response (200)
Keys are scoped to your workspace, up to 64 characters (A-Z a-z 0-9 . _ : -), and permanently identify their post - there is no expiry window to race against. Deleting the post frees its key. Concurrent retries are safe: a unique database constraint guarantees only one post can ever own a key. Works on POST /social/posts and POST /social/posts/schedule (including queue scheduling).

Layer 2: duplicate-content guard

Independent of headers, creating identical content in the same workspace within 24 hours returns 409 DUPLICATE_CONTENT with the existing post’s id:
409 response
This catches the classic mis-wired-cron bug even when no idempotency key was sent. Intentional re-posts opt out per request with "allow_duplicates": true in the body. Posts that ended failed or were unpublished never block a re-post.

How the layers interact

  1. Same idempotency key seen before → 200 replay of the original post (wins over the duplicate guard - a retry is not a duplicate).
  2. No (or new) key, identical content within 24h → 409 DUPLICATE_CONTENT.
  3. Otherwise → the post is created normally.

Retry rules of thumb