API reference

REST over HTTPS, JSON in and out, workspace-scoped bearer keys. Create keys under Settings → API keys; they look like cc_live_… and are shown once.

Authentication

Authorization: Bearer cc_live_xxxxxxxxxxxxxxxx

POST/media

Stage a video. Returns a presigned upload URL — PUT the file bytes there, then the asset is ready to attach to posts.

curl -X POST https://crosscast.io/api/v1/media \
  -H "Authorization: Bearer cc_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "filename": "final.mp4", "bytes": 18422011 }'

# → 201
{ "id": "med_01hxkq...", "upload_url": "https://...", "expires_in": 3600 }

curl -X PUT "<upload_url>" --data-binary @final.mp4 -H "Content-Type: video/mp4"

POST/posts

Create a post. Targets default to the channel's accounts; captions default to the channel's templates rendered with your title. Both are overridable per call.

curl -X POST https://crosscast.io/api/v1/posts \
  -H "Authorization: Bearer cc_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "mapsofwhy",
    "media_id": "med_01hxkq...",
    "title": "why the mississippi runs backwards",
    "schedule": "next_slot",          // or "now", or "2026-08-14T17:00:00Z"
    "captions": {                      // optional per-platform overrides
      "tiktok": "why the mississippi runs backwards #maps #geography"
    },
    "cover_offset_ms": 1200,           // optional
    "accounts": ["acc_01..."]          // optional subset of the channel
  }'

# → 201
{ "id": "post_01hxkr...", "status": "scheduled",
  "targets": [
    { "id": "tgt_01...", "platform": "tiktok",    "account": "@mapsofwhy", "at": "2026-08-14T17:00:00Z" },
    { "id": "tgt_02...", "platform": "instagram", "account": "@mapsofwhy", "at": "2026-08-14T17:00:00Z" },
    { "id": "tgt_03...", "platform": "youtube",   "account": "mapsofwhy",  "at": "2026-08-14T17:00:00Z" }
  ] }

GET/posts/:id

Status, permalinks, and the latest metrics snapshot per target.

curl https://crosscast.io/api/v1/posts/post_01hxkr... \
  -H "Authorization: Bearer cc_live_..."

# → 200
{ "id": "post_01hxkr...", "status": "published",
  "targets": [
    { "platform": "instagram", "status": "published",
      "permalink": "https://www.instagram.com/reel/...",
      "metrics": { "views": 8211, "likes": 402, "avg_watch_time_ms": 11400 } },
    { "platform": "tiktok", "status": "on_phone",
      "note": "delivered to TikTok inbox; finish in-app" }
  ] }

Errors

Standard HTTP status codes with a stable machine-readable shape. Platform-side failures include the platform's own message verbatim — debugging distribution should never require guessing.

{ "error": { "code": "quota_exceeded",
  "message": "YouTube upload quota reached for today (6/6). Next reset 08:00 UTC." } }