preflight_failed error carrying the rule id that fired, plus a ruleUrl field with the absolute link to this page set — so a client doesn’t need to know the slug convention to deep-link a failure straight to its docs.
Why preflight
The most-cited developer complaint about social media APIs is that constraints are documented somewhere, but the runtime error doesn’t say which constraint you tripped. Examples from the research corpus that drove this product:- Instagram Reels rejecting Google Drive URLs as
OAuthException 2207052. - LinkedIn returning generic 422s for URN format mismatches.
- Threads returning HTTP 200 with a status code embedded in the body.
Reading a rule id
Rule ids look like<platform>.<surface>.<check>:
Rule catalog
Bluesky
bluesky.text.non_emptybluesky.text.max_graphemesbluesky.media.image_video_exclusivebluesky.media.count_maxbluesky.media.alt_text_max_graphemesbluesky.media.mime_allowedbluesky.media.image_size_maxbluesky.media.video_size_maxbluesky.video.quota_exhaustedbluesky.video.job_failedbluesky.video.transcode_timeoutbluesky.first_comment.non_emptybluesky.first_comment.max_graphemes
Threads
threads.text.requiredthreads.text.max_graphemesthreads.media.count_maxthreads.media.alt_text_max_graphemesthreads.media.mime_allowedthreads.media.image_size_maxthreads.media.video_size_maxthreads.container.expiredthreads.container.error
instagram.media.requiredinstagram.text.max_graphemesinstagram.media.count_maxinstagram.media.alt_text_max_graphemesinstagram.media.mime_allowedinstagram.media.image_size_maxinstagram.media.video_size_maxinstagram.media.reachable— the canonicalOAuthException 2207052translator.instagram.media.aspect_ratio
facebook.text.requiredfacebook.text.max_graphemesfacebook.media.image_video_exclusivefacebook.media.count_maxfacebook.media.mime_allowedfacebook.media.image_size_maxfacebook.media.video_size_maxfacebook.pages.none
linkedin.text.non_emptylinkedin.text.max_graphemeslinkedin.author.urn_formatlinkedin.author.org_not_supportedlinkedin.author.unresolvedlinkedin.visibility.enum
pinterest.board.requiredpinterest.media.requiredpinterest.media.single_onlypinterest.image.mime_allowedpinterest.image.size_maxpinterest.image_url.reachablepinterest.destination_url.reachablepinterest.url.reachablepinterest.video.cover_requiredpinterest.video.mime_allowedpinterest.video.size_maxpinterest.cover_image_url.reachablepinterest.cover_image.mime_allowedpinterest.media.register_failedpinterest.video.upload_failedpinterest.video.transcode_failedpinterest.video.transcode_timeout
Twitter / X
twitter.text.non_emptytwitter.text.max_graphemestwitter.media.count_maxtwitter.media.image_video_exclusivetwitter.media.alt_text_max_graphemestwitter.media.mime_allowedtwitter.media.image_size_maxtwitter.media.gif_size_maxtwitter.media.video_size_maxtwitter.media.video_processing_failedtwitter.media.processing_timeout
Cross-platform
media.unknown— referenced media id doesn’t exist or is out of scope.media.bytes_inline_unsupported—bytesBase64not allowed for this surface.meta.container.expired— IG/Threads container ttl exceeded.
Validation without publishing
WhenPOST /v1/posts/validate ships, you’ll be able to run the same preflight without the upstream call — useful in CI or before queueing a scheduled post. Today, the same validation runs synchronously on POST /v1/posts and returns the rule id on the first failure.
