In short
POST /api/v1/posts creates a multi-network job with one leg per platform. Status can be processing, succeeded, partial, or failed. Charge is per publish_leg. Retry only failed legs with POST /api/v1/posts/{id}/retry. Always send Idempotency-Key on create.
Request shape
Body includes text, platforms[] (facebook | instagram | linkedin | bluesky | mastodon), optional mediaUrls[] (HTTPS), optional scheduleAt (UTC), and platformOptions for network-specific fields.
{
"text": "Summer hours start Monday.",
"platforms": ["facebook", "linkedin", "bluesky"],
"mediaUrls": ["https://cdn.example.com/promo.jpg"],
"scheduleAt": null
}Validate first
POST /api/v1/posts/validate costs 1 token and returns per-network valid/errors plus a tokensEstimate. Use it in composer UIs before spending publish tokens.
Legs and status machine
Each network is a leg with status pending, publishing, succeeded, failed, or skipped. Post status aggregates legs: succeeded (all good), partial (mix), failed (all failed), scheduled, processing.
- partial is normal when one network rejects media or quota
- Inspect leg.error.code and message for user-facing fixes
- retryAvailable on a leg indicates retry is appropriate
Retry
POST /api/v1/posts/{id}/retry with optional platforms[] re-attempts failed legs only. Each attempt costs posts.retry_leg (10 tokens).
Token math
Immediate publish ≈ 10 × number of platforms (+ media.validate if used). Schedule adds 2 when the post is stored; legs charge when the timer fires.

