Errors and retries
SocialClaw's error model: one JSON error envelope across every route, validation that fails early and specifically, recorded publish attempts, retryable vs permanent failures, and idempotency keys that make retries safe.
One error shape everywhere. Every JSON API route returns the same envelope on failure — branch on code, not on message:
{
"ok": false,
"code": "validation_failed",
"message": "Human-readable explanation of what went wrong.",
"details": { "...": "optional route-specific context" }
}
Validation failures. POST /v1/posts/validate fails early and specifically: provider rule violations, media limits, missing accounts, and bad publish times are reported per post, before any run exists. Treat a failed validation as a fix-the-document signal, not a retry signal. Apply performs the same preflight, so a schedule that validated cleanly can still be rejected if state changed in between.
Publish failures and attempts. When a provider rejects a post at publish time, the post's status becomes failed and every attempt is recorded with the provider's error:
curl -sS https://getsocialclaw.com/v1/posts/post_123/attempts \
-H "Authorization: Bearer $SOCIALCLAW_API_KEY"
curl -sS -X POST https://getsocialclaw.com/v1/posts/post_123/retry \
-H "Authorization: Bearer $SOCIALCLAW_API_KEY"
Transient provider failures (network errors, upstream hiccups) are marked retryable — retry them; permanent rejections need the content fixed instead. Cancel a scheduled post before it publishes with DELETE /v1/posts/{postId}. Stuck in an ambiguous state? socialclaw posts reconcile --post-id re-checks the provider for the post's true status.
Retry without duplicating. Network failures on apply are the dangerous ones — you may not know whether the run was created. The idempotencyKey exists exactly for this: resend the identical document with the same key and the API returns the existing run instead of creating a second one.