Docs: add /api/posts contract, publish a video now or at publish_at (IG, X, LinkedIn, YouTube)

Merged
SW
1d ago
+784-8

Contract for publishing a video to a connected social account, now or at a set time, authored in the maintained docs source (content/docs/source). Step 1 of the merge order in recoupable/app#2241: docs (this PR, then the recoupable/docs publication copy) → database (scheduled_posts) → api publish-now → api scheduling + cancel.

Endpoints (new Connectors → Publishing nav group)

MethodPathPage
POST/api/postsCreate Post: 202 {id, status} + Location; status is publishing (no publish_at) or scheduled
GET/api/postsList Posts: filters status, platform, limit, offset; standard account_id override
GET/api/posts/{id}Get Post: polling target; post_url, error_message, text_verified
DELETE/api/posts/{id}Cancel Post: only while scheduled (409 otherwise)

Shape decisions (Sweets, 2026-10-13, modeled on OpusClip's social-posting API)

  • One endpoint for now and later. publish_at omitted = publish now.
  • One target account per call (account_id + platform, plus sub_account_id for a LinkedIn Page). A multi-platform slate is a client-side loop; each post fails or succeeds on its own.
  • Media by URL (video_url, cover_url).
  • One copy shape for every platform (title, description, privacy, tags), with a per-platform table of which fields are used, which are required and the limits (X 280 weighted, YT title 100, IG 2,200, LI 3,000). Limits are a 400 at create time, not a failure at publish time.
  • Lifecycle scheduled → publishing → posted | failed | cancelled. A YouTube upload that hits the shared daily quota ends failed with the platform's message in error_message.
  • No custom thumbnail on YouTube (cover_url unused there): API-set Shorts thumbnails rendered blank on four of our videos (owner rule 2026-10-13).
  • Out of v1: TikTok (audit), AI-written copy.

Mirrors the Music endpoints (POST /api/music 202 + Location → GET /api/music/{generationId}, list with status/limit/offset, {status: "error", missing_fields, error} envelope). No credit behavior documented, since none is decided.

Pending availability

All four operations carry x-recoup-availability: pending and an Availability: pending notice, because no API route exists yet; the Documentation contract inventory check requires that for unmatched documented routes. Remove both when the api publish-now PR ships.

Coordinated PRs and merge order

  1. recoupable/api#1034: refreshes the social.json hash in lib/contracts/fixtures/published-docs.json (no runtime change). This branch's operation-inventory.json is pinned to its commit 031a27d.
  2. This PR, re-pinned to api#1034's merge commit after it merges (scripts/refresh-contract-inventory.py --api <api main>).
  3. recoupable/docs#375, re-synced to this PR's merge commit.

Checks

  • social.json diff is purely additive (load → add → dump reproduces the original byte-for-byte). mintlify openapi-check: valid.
  • pnpm docs:build (inventory, manifest, navigation regenerated and committed), pnpm docs:check 7/7, vitest run tests 351/351, build-docs.test.ts pass.
  • Rendered locally at /docs/api-reference/publishing/{create,list,get,cancel}: all 200, Connectors → Publishing nav group present, and the per-platform field table renders on Create Post. (It is in the operation description because schema-level descriptions are not rendered by the docs page.)
  • New pages live under api-reference/publishing/ because api-reference/posts/get is already the scraped Get Artist Posts page.
  • Publication copy: recoupable/docs#375, synced from this branch's commit with scripts/sync-legacy-docs.py; it gets re-synced to the merge commit after this merges.

Also in this PR: docs sidebar keeps its place

Clicking a sidebar item used to reload the page with the sidebar nav scrolled back to the top, losing the selected item. DocsSidebar (components/docs/docs-interactive.tsx) now saves the nav's scroll position in sessionStorage, restores it on each page, and centers the current item when it would otherwise be out of view. Verified on preview with before/after screenshots.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation
    • Added API reference pages for creating, listing, retrieving, and cancelling social posts.
    • The documentation describes video publishing to connected YouTube, Instagram, X, and LinkedIn accounts, including scheduling, platform-specific requirements, filters, pagination, and cancellation rules.
    • These endpoints are marked as pending implementation and are not yet available.
    • Added a Publishing section to the Connectors navigation for easier access to the new reference pages.