{"openapi":"3.1.0","info":{"title":"Reelspan API","version":"1.0.0","description":"Publish videos, photos and text to every network from one call.\n\nAuthenticate with `Authorization: Apikey <your key>`. Create keys in the dashboard under **API keys**.\nThe publish endpoints accept the same multipart fields and return the same JSON as Upload-Post, so existing\nintegrations work by changing the base URL."},"servers":[{"url":"https://app.reelspan.com","description":"Reelspan API"}],"components":{"securitySchemes":{"ApiKey":{"type":"apiKey","in":"header","name":"Authorization","description":"Send `Apikey <your key>`."}},"schemas":{"Me":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string","example":"Token is valid"},"email":{"type":["string","null"]},"plan":{"type":"string","example":"starter"},"preferences":{"type":"object","properties":{"weekStartDay":{"anyOf":[{"type":"number","enum":[0]},{"type":"number","enum":[1]}]}},"required":["weekStartDay"]},"api_usage":{"type":"object","properties":{"count":{"type":"integer"},"limit":{"type":["integer","null"]},"last_reset":{"type":"string"}},"required":["count","limit","last_reset"]}},"required":["success","message","email","plan","preferences","api_usage"]},"Error":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"message":{"type":"string"},"error":{"type":"string"},"error_code":{"type":"string"}},"required":["success"]},"Profile":{"type":"object","properties":{"username":{"type":"string","example":"firestack"},"display_name":{"type":["string","null"]},"created_at":{"type":"string"},"social_accounts":{"type":"object","additionalProperties":{},"description":"One entry per network: account details when connected, \"\" when not"}},"required":["username","display_name","created_at","social_accounts"]},"Captions":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"ai_generated":{"type":"boolean","enum":[true]},"remaining_analyses":{"type":"number"}},"required":["success","ai_generated","remaining_analyses"],"additionalProperties":{},"description":"One object per platform, e.g. youtube: {title, description, tags}, instagram: {caption}, x: {text}"},"UploadPhotosForm":{"type":"object","properties":{"user":{"type":"string","description":"Profile username"},"platform[]":{"type":"array","items":{"type":"string"},"description":"instagram, facebook, x, threads, bluesky, linkedin, pinterest"},"photos[]":{"type":"array","items":{"type":"string"},"description":"Photo files (binary) or public https URLs, in order; up to 35"},"photo_media_ids[]":{"type":"array","items":{"type":"string"},"description":"Photos uploaded earlier with POST /api/media/upload?kind=photo"},"<platform>_photos[]":{"type":"array","items":{"type":"string"},"description":"Public URLs a platform gets instead of photos[], e.g. pinterest_photos[] cropped to one shape"},"<platform>_photo_media_ids[]":{"type":"array","items":{"type":"string"},"description":"Uploaded photos a platform gets instead, e.g. instagram_photo_media_ids[]"},"title":{"type":"string","description":"Caption"},"async_upload":{"type":"string","enum":["true","false"]},"scheduled_date":{"type":"string"},"timezone":{"type":"string"}},"required":["user","platform[]","title"],"additionalProperties":{},"description":"Pinterest carousels need every photo in one shape and Instagram 4:5 to 1.91:1; non-JPEG photos are converted for Instagram."},"UploadTextForm":{"type":"object","properties":{"user":{"type":"string","description":"Profile username"},"platform[]":{"type":"array","items":{"type":"string"},"description":"x, bluesky, threads, linkedin, facebook (YouTube Community posts, TikTok, Instagram and Pinterest have no text posts in their APIs)"},"title":{"type":"string","description":"The text of the post; long text becomes a thread on X and Bluesky"},"facebook_link":{"type":"string","description":"A link Facebook shows as a preview"},"scheduled_date":{"type":"string"},"timezone":{"type":"string"}},"required":["user","platform[]","title"],"additionalProperties":{}},"UploadVideoForm":{"type":"object","properties":{"user":{"type":"string","description":"Profile username"},"platform[]":{"type":"array","items":{"type":"string"},"description":"Networks to publish to, repeated: youtube, instagram, facebook, x, tiktok, ..."},"video":{"type":"string","description":"The video file (binary), or a public https URL"},"title":{"type":"string","description":"Default caption; required for YouTube"},"description":{"type":"string"},"async_upload":{"type":"string","enum":["true","false"],"description":"Return immediately with a request_id"},"scheduled_date":{"type":"string","description":"ISO-8601; returns 202 with a job_id"},"timezone":{"type":"string","description":"IANA zone for scheduled_date (default UTC)"},"external_id":{"type":"string"},"request_id":{"type":"string","description":"Your own id, 8-100 characters, to poll even if the response is lost"},"first_comment":{"type":"string","description":"Posted as the first comment (a reply on X, Bluesky and Threads) right after the post goes live. `{platform}_first_comment` overrides it for one platform. Where a platform has no comments API, or refuses it, the post still counts and its result carries `first_comment` and a warning."},"video_media_id":{"type":"string","description":"A video uploaded earlier with POST /api/media/upload, instead of `video`"},"bluesky_compress":{"type":"string","enum":["true","false"],"description":"Compress a video over 100 MB so Bluesky takes it (only when set)"},"privacy_level":{"type":"string","description":"TikTok: PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR or SELF_ONLY"},"post_mode":{"type":"string","enum":["DIRECT_POST","MEDIA_UPLOAD"],"description":"TikTok: MEDIA_UPLOAD sends it to the TikTok inbox to finish in the app"},"youtube_title":{"type":"string"},"youtube_description":{"type":"string"},"tags[]":{"type":"array","items":{"type":"string"}},"privacyStatus":{"type":"string","enum":["public","unlisted","private"]},"instagram_title":{"type":"string"},"facebook_title":{"type":"string"},"x_title":{"type":"string"},"tiktok_title":{"type":"string"}},"required":["user","platform[]","video"],"additionalProperties":{},"description":"Accepts every Upload-Post `/api/upload` field. Only the common ones are listed here."}},"parameters":{}},"paths":{"/api/uploadposts/me":{"get":{"tags":["Account"],"summary":"Check the API key and read the account plan and usage","security":[{"ApiKey":[]}],"responses":{"200":{"description":"The key is valid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"description":"Missing, invalid or expired key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/users/notifications":{"get":{"tags":["Webhooks"],"security":[{"ApiKey":[]}],"summary":"Read the account webhook settings","responses":{"200":{"description":"Settings","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"notifications":{"type":"object","additionalProperties":{}}},"required":["success","notifications"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Webhooks"],"security":[{"ApiKey":[]}],"summary":"Set the account webhook","description":"Events: upload_completed, social_account_connected, social_account_disconnected, social_account_reauth_required. Deliveries are signed: `X-Reelspan-Signature: sha256=HMAC_SHA256(secret, \"<X-Reelspan-Timestamp>.<raw body>\")`, and retried for up to 24 hours.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"channels":{"type":"object","properties":{"webhook":{"type":"boolean"}},"additionalProperties":{}},"webhook_url":{"type":"string"},"webhook_events":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"object","additionalProperties":{"type":"boolean"}}],"description":"Array of event names or an object of booleans"}}}}}},"responses":{"200":{"description":"Saved","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"notifications":{"type":"object","additionalProperties":{}}},"required":["success","notifications"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Webhooks"],"security":[{"ApiKey":[]}],"summary":"Remove the account webhook","responses":{"200":{"description":"Removed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"}},"required":["success","message"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/users/webhook-secret":{"post":{"tags":["Webhooks"],"security":[{"ApiKey":[]}],"summary":"Rotate the account webhook signing secret","responses":{"200":{"description":"New secret","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"webhook_secret":{"type":"string"}},"required":["success","webhook_secret"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/users/notifications/test":{"post":{"tags":["Webhooks"],"security":[{"ApiKey":[]}],"summary":"Send a test event to the account webhook","responses":{"200":{"description":"Queued","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"delivery_id":{"type":"string"}},"required":["success","delivery_id"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/users/profile-webhook":{"get":{"tags":["Webhooks"],"security":[{"ApiKey":[]}],"summary":"Read a profile’s own webhook","parameters":[{"schema":{"type":"string"},"required":true,"name":"profile_username","in":"query"}],"responses":{"200":{"description":"Settings","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"webhook":{"type":"object","additionalProperties":{}}},"required":["success","webhook"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Webhooks"],"security":[{"ApiKey":[]}],"summary":"Set a profile’s own webhook (sent in addition to the account webhook)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"profile_username":{"type":"string"},"webhook_url":{"type":"string"},"webhook_events":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"object","additionalProperties":{"type":"boolean"}}],"description":"Array of event names or an object of booleans"}},"required":["profile_username","webhook_url"]}}}},"responses":{"200":{"description":"Saved","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"webhook":{"type":"object","additionalProperties":{}}},"required":["success","webhook"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Webhooks"],"security":[{"ApiKey":[]}],"summary":"Remove a profile’s webhook","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"profile_username":{"type":"string"}},"required":["profile_username"]}}}},"responses":{"200":{"description":"Removed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"}},"required":["success","message"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/webhooks/deliveries":{"get":{"tags":["Webhooks"],"security":[{"ApiKey":[]}],"summary":"Recent webhook deliveries with their status","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Deliveries","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"deliveries":{"type":"array","items":{"type":"object","additionalProperties":{}}}},"required":["success","deliveries"]}}}}}}},"/api/uploadposts/webhooks/deliveries/{id}/redeliver":{"post":{"tags":["Webhooks"],"security":[{"ApiKey":[]}],"summary":"Send a delivery again","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Queued","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]}},"required":["success"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/users/generate-jwt":{"post":{"security":[{"ApiKey":[]}],"tags":["White-label"],"summary":"Create a hosted connect link for a profile","description":"Returns a link (valid 48 hours) where your client connects their own accounts to the profile, without a Reelspan login. Logo, texts, labels and theme need a plan with white-label; the settings are remembered for the next link.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"redirect_url":{"type":"string","maxLength":2000,"format":"uri"},"logo_image":{"type":"string","maxLength":2000,"format":"uri"},"redirect_button_text":{"type":"string","maxLength":60},"connect_title":{"type":"string","maxLength":120},"connect_description":{"type":"string","maxLength":500},"platforms":{"type":"array","items":{"type":"string"},"maxItems":20},"show_calendar":{"type":"boolean"},"readonly_calendar":{"type":"boolean"},"language":{"type":"string","enum":["en","es","de","fr","pt","pl","tr"]},"ui_labels":{"type":["object","null"],"additionalProperties":{"type":"string","maxLength":300}},"connect_theme":{"type":"string","enum":["light","dark","auto"]},"username":{"type":"string"}},"required":["username"]}}}},"responses":{"200":{"description":"Link","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"access_url":{"type":"string"},"duration":{"type":"string"},"warnings":{"type":"array","items":{"type":"string"}}},"required":["success","access_url","duration"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid key or token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan does not include white-label","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Profile not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/users/validate-jwt":{"get":{"tags":["White-label"],"summary":"Check a connect token (send it as Bearer)","responses":{"200":{"description":"Valid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"isValid":{"type":"boolean","enum":[true]},"profile":{"type":"object","additionalProperties":{}}},"required":["success","isValid","profile"]}}}},"401":{"description":"Invalid or expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/oauth/{platform}/start":{"post":{"tags":["White-label"],"summary":"Start an OAuth connection (Connect API)","description":"For your own connect page. Authenticate with a connect token (Bearer, from generate-jwt) or an API key plus `profile`. Send the user to `authorize_url`; they come back to `redirect_url` with `connect_status=success|cancelled|error`, `platform`, and on errors `error_code` and `error_description`.","parameters":[{"schema":{"type":"string"},"required":true,"name":"platform","in":"path"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"profile":{"type":"string"},"redirect_url":{"type":"string","maxLength":2000,"format":"uri"}}}}}},"responses":{"200":{"description":"Started","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"platform":{"type":"string"},"authorize_url":{"type":"string"},"state":{"type":"string"},"expires_in":{"type":"number"}},"required":["success","platform","authorize_url","state","expires_in"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid key or token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan does not include white-label","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Profile not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/users":{"post":{"tags":["Profiles"],"security":[{"ApiKey":[]}],"summary":"Create a profile","description":"A profile is the `user` you publish as. It can connect one account per network.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string","pattern":"^[A-Za-z0-9_@-]{1,64}$"},"display_name":{"type":"string","maxLength":100}},"required":["username"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"profile":{"$ref":"#/components/schemas/Profile"}},"required":["success","profile"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan limit or key scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Profile not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Username taken","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["Profiles"],"security":[{"ApiKey":[]}],"summary":"List profiles and their connected accounts","responses":{"200":{"description":"Profiles","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"limit":{"type":"number"},"plan":{"type":"string"},"profiles":{"type":"array","items":{"$ref":"#/components/schemas/Profile"}}},"required":["success","limit","plan","profiles"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan limit or key scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Profile not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Profiles"],"security":[{"ApiKey":[]}],"summary":"Delete a profile and disconnect all its accounts","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string"}},"required":["username"]}}}},"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"}},"required":["success","message"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan limit or key scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Profile not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/users/{username}":{"get":{"tags":["Profiles"],"security":[{"ApiKey":[]}],"summary":"Get one profile","parameters":[{"schema":{"type":"string"},"required":true,"name":"username","in":"path"}],"responses":{"200":{"description":"Profile","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"profile":{"$ref":"#/components/schemas/Profile"}},"required":["success","profile"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan limit or key scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Profile not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Profiles"],"security":[{"ApiKey":[]}],"summary":"Change a profile’s display name","parameters":[{"schema":{"type":"string"},"required":true,"name":"username","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"display_name":{"type":["string","null"],"maxLength":100}},"required":["display_name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"profile":{"$ref":"#/components/schemas/Profile"}},"required":["success","profile"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan limit or key scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Profile not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/users/social":{"delete":{"tags":["Profiles"],"security":[{"ApiKey":[]}],"summary":"Disconnect one network from a profile","description":"Idempotent: disconnecting a network that is not connected also returns 200.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"profile_username":{"type":"string"},"social_platform":{"type":"string"}},"required":["profile_username","social_platform"]}}}},"responses":{"200":{"description":"Disconnected","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"}},"required":["success","message"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan limit or key scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Profile not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/status":{"get":{"tags":["Publishing"],"summary":"Status of a publish request, per platform","description":"Poll every 5 seconds or more. Only platforms that have finished appear in `results`.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":false,"name":"request_id","in":"query"},{"schema":{"type":"string"},"required":false,"name":"job_id","in":"query"}],"responses":{"200":{"description":"Status","content":{"application/json":{"schema":{"type":"object","properties":{"request_id":{"type":"string"},"status":{"type":"string"},"completed":{"type":"number"},"total":{"type":"number"},"results":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string"},"success":{"type":"boolean"},"post_url":{"type":["string","null"]},"error_message":{"type":["string","null"]}},"required":["platform","success","post_url","error_message"],"additionalProperties":{}}}},"required":["request_id","status","completed","total","results"],"additionalProperties":{}}}}},"404":{"description":"Unknown request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/history":{"get":{"tags":["Publishing"],"summary":"Upload history, one row per platform post","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"number","default":10},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"platform","in":"query"},{"schema":{"type":"string","enum":["success","failed"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"string"},"required":false,"name":"profile_username","in":"query"},{"schema":{"type":"string"},"required":false,"name":"profile","in":"query"},{"schema":{"type":"string","maxLength":200},"required":false,"name":"request_id","in":"query"},{"schema":{"type":"string","maxLength":200},"required":false,"name":"job_id","in":"query"},{"schema":{"type":"string","maxLength":200},"required":false,"name":"external_id","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"string","format":"date"}]},"required":false,"name":"start","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"string","format":"date"}]},"required":false,"name":"end","in":"query"}],"responses":{"200":{"description":"History","content":{"application/json":{"schema":{"type":"object","properties":{"history":{"type":"array","items":{"type":"object","additionalProperties":{}}},"in_progress":{"type":"array","items":{"type":"object","additionalProperties":{}}},"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"}},"required":["history","in_progress","total","page","limit"]}}}},"400":{"description":"Invalid filters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/schedule":{"get":{"security":[{"ApiKey":[]}],"tags":["Scheduling"],"summary":"List scheduled posts","parameters":[{"schema":{"type":"string"},"required":false,"name":"profile_username","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"from","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"to","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":["integer","null"],"minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Scheduled posts","content":{"application/json":{"schema":{"type":"object","properties":{"scheduled_posts":{"type":"array","items":{"type":"object","additionalProperties":{}}},"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"}},"required":["scheduled_posts","total","limit","offset"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already publishing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/schedule/{job_id}":{"get":{"security":[{"ApiKey":[]}],"tags":["Scheduling"],"summary":"Get a scheduled post","parameters":[{"schema":{"type":"string"},"required":true,"name":"job_id","in":"path"}],"responses":{"200":{"description":"Scheduled post","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already publishing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"security":[{"ApiKey":[]}],"tags":["Scheduling"],"summary":"Reschedule or edit a scheduled post","description":"Change the time and text fields. The media, profile and networks cannot change. Fails with 409 once publishing has started or within a minute of the time.","parameters":[{"schema":{"type":"string"},"required":true,"name":"job_id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"scheduled_date":{"type":"string"},"timezone":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"fields":{"type":"object","additionalProperties":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}},{"type":"null"}]},"description":"Any upload field; null removes it"}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already publishing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"security":[{"ApiKey":[]}],"tags":["Scheduling"],"summary":"Cancel a scheduled post and refund its upload credits","parameters":[{"schema":{"type":"string"},"required":true,"name":"job_id","in":"path"}],"responses":{"200":{"description":"Cancelled","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"credits_refunded":{"type":"number"}},"required":["success","message","credits_refunded"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already publishing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/queue/settings":{"get":{"security":[{"ApiKey":[]}],"tags":["Queue"],"summary":"Read a profile’s queue: posting slots, days and capacity","parameters":[{"schema":{"type":"string"},"required":true,"name":"profile_username","in":"query"}],"responses":{"200":{"description":"Settings","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"queue_settings":{"type":"object","additionalProperties":{}}},"required":["success","queue_settings"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already publishing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"security":[{"ApiKey":[]}],"tags":["Queue"],"summary":"Set a profile’s queue","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"profile_username":{"type":"string"},"timezone":{"type":"string"},"slots":{"type":"array","items":{"type":"object","properties":{"hour":{"type":"integer","minimum":0,"maximum":23},"minute":{"type":"integer","minimum":0,"maximum":59}},"required":["hour","minute"]},"maxItems":24},"days_of_week":{"type":"array","items":{"type":"integer","minimum":0,"maximum":6},"description":"0 = Monday"},"max_posts_per_slot":{"type":"integer","minimum":1,"maximum":100}},"required":["profile_username"]}}}},"responses":{"200":{"description":"Saved","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"queue_settings":{"type":"object","additionalProperties":{}}},"required":["success","queue_settings"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already publishing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/queue/preview":{"get":{"security":[{"ApiKey":[]}],"tags":["Queue"],"summary":"Upcoming queue slots and how full they are","parameters":[{"schema":{"type":"string"},"required":true,"name":"profile_username","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":50,"default":10},"required":false,"name":"count","in":"query"}],"responses":{"200":{"description":"Slots","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already publishing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/queue/next-slot":{"get":{"security":[{"ApiKey":[]}],"tags":["Queue"],"summary":"The next slot with room","parameters":[{"schema":{"type":"string"},"required":true,"name":"profile_username","in":"query"}],"responses":{"200":{"description":"Next slot","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already publishing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/queue/slot-full":{"post":{"security":[{"ApiKey":[]}],"tags":["Queue"],"summary":"Mark a slot as full","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"profile_username":{"type":"string"},"slot_datetime":{"type":"string","format":"date-time"}},"required":["profile_username","slot_datetime"]}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already publishing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"security":[{"ApiKey":[]}],"tags":["Queue"],"summary":"Open a slot that was marked full","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"profile_username":{"type":"string"},"slot_datetime":{"type":"string","format":"date-time"}},"required":["profile_username","slot_datetime"]}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already publishing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/posts/retry":{"post":{"security":[{"ApiKey":[]}],"tags":["Publishing"],"summary":"Retry the platforms that failed","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"request_id":{"type":"string"},"job_id":{"type":"string"},"platforms":{"type":"array","items":{"type":"string"},"description":"Retry only these platforms"},"fields":{"type":"object","additionalProperties":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"description":"Settings to change before retrying (same names as the upload fields); an empty string removes one"}}}}}},"responses":{"200":{"description":"Re-queued","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"request_id":{"type":"string"},"message":{"type":"string"},"platforms":{"type":"array","items":{"type":"string"}}},"required":["success","request_id","message","platforms"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Nothing to do","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/facebook/pages":{"get":{"security":[{"ApiKey":[]}],"tags":["Lookups"],"summary":"Facebook Pages connected to a profile","parameters":[{"schema":{"type":"string"},"required":false,"name":"profile","in":"query"},{"schema":{"type":"string"},"required":false,"name":"profile_username","in":"query"},{"schema":{"type":"string"},"required":false,"name":"user","in":"query"}],"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Nothing to do","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/pinterest/boards":{"get":{"security":[{"ApiKey":[]}],"tags":["Lookups"],"summary":"Pinterest boards of a profile’s account","parameters":[{"schema":{"type":"string"},"required":false,"name":"profile","in":"query"},{"schema":{"type":"string"},"required":false,"name":"profile_username","in":"query"},{"schema":{"type":"string"},"required":false,"name":"user","in":"query"}],"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Nothing to do","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"security":[{"ApiKey":[]}],"tags":["Lookups"],"summary":"Create a Pinterest board on a profile’s account","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"profile":{"type":"string"},"profile_username":{"type":"string"},"user":{"type":"string"},"name":{"type":"string","minLength":1,"maxLength":50}},"required":["name"]}}}},"responses":{"200":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"board":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]}},"required":["success","board"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Nothing to do","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/tiktok/creator-info":{"get":{"security":[{"ApiKey":[]}],"tags":["Lookups"],"summary":"What a TikTok account may post: privacy levels, interactions and its longest video","parameters":[{"schema":{"type":"string"},"required":false,"name":"profile","in":"query"},{"schema":{"type":"string"},"required":false,"name":"profile_username","in":"query"},{"schema":{"type":"string"},"required":false,"name":"user","in":"query"}],"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Nothing to do","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/linkedin/pages":{"get":{"security":[{"ApiKey":[]}],"tags":["Lookups"],"summary":"LinkedIn company pages a profile can post as","parameters":[{"schema":{"type":"string"},"required":false,"name":"profile","in":"query"},{"schema":{"type":"string"},"required":false,"name":"profile_username","in":"query"},{"schema":{"type":"string"},"required":false,"name":"user","in":"query"}],"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Nothing to do","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/adapt-captions":{"post":{"tags":["AI"],"summary":"Write captions for each network from whatever the post has","description":"Give any of: your caption (`text`, kept as the facts and adapted per network), a video as `frames` plus its `audio` (the speech is transcribed first), or `images`. Uses one AI credit.","security":[{"ApiKey":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"platforms":{"type":"array","items":{"type":"string"}},"text":{"type":"string","maxLength":5000,"description":"Your caption: kept as the facts and adapted per network"},"notes":{"type":"string","maxLength":4000,"description":"Hints for the AI (facts, names, the angle) without writing the caption yourself"},"frames":{"type":"array","items":{"type":"string","maxLength":3000000,"pattern":"^data:image\\/(jpeg|png|webp);base64,[A-Za-z0-9+/=]+$"},"maxItems":8,"description":"Frames from the video, in order"},"images":{"type":"array","items":{"type":"string","maxLength":3000000,"pattern":"^data:image\\/(jpeg|png|webp);base64,[A-Za-z0-9+/=]+$"},"maxItems":10,"description":"The post’s photos"},"audio":{"type":"object","properties":{"data":{"type":"string","maxLength":16000000,"pattern":"^[A-Za-z0-9+/=]+$"},"format":{"type":"string","enum":["wav","mp3"]}},"required":["data","format"],"description":"The video’s audio, base64 (16 kHz mono WAV is plenty)"},"duration":{"type":"number","minimum":0,"description":"Video length in seconds"},"media_id":{"type":"string","maxLength":64,"description":"A video uploaded with POST /api/media/upload: frames and sound are taken from it on the server"},"photo_media_ids":{"type":"array","items":{"type":"string","maxLength":64},"maxItems":10,"description":"Photos uploaded with POST /api/media/upload"},"kind":{"type":"string","enum":["video","photo","text"]},"language":{"type":"string","maxLength":40}}}}}},"responses":{"200":{"description":"Captions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Captions"}}}},"400":{"description":"Nothing to write from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"No credits left","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/rewrite-captions":{"post":{"tags":["AI"],"summary":"Adapt existing captions to each network","description":"Keeps the facts, changes style, length and hashtags per network. Uses one AI credit.","security":[{"ApiKey":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"object","additionalProperties":{},"description":"Your current captions, e.g. {\"youtube\": {\"title\": \"...\"}}"},"platforms":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20},"language":{"type":"string","maxLength":40},"instructions":{"type":"string","maxLength":1000}},"required":["content"]}}}},"responses":{"200":{"description":"Captions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Captions"}}}},"429":{"description":"No credits left","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/analytics/{profile_username}":{"get":{"security":[{"ApiKey":[]}],"tags":["Analytics"],"summary":"Account totals per network (followers, views, posts…)","description":"Keyed by platform. Networks whose stats are unavailable return `{ error, error_code }`. Cached for 10 minutes.","parameters":[{"schema":{"type":"string"},"required":true,"name":"profile_username","in":"path"},{"schema":{"type":"string","description":"Comma-separated; default all connected"},"required":false,"description":"Comma-separated; default all connected","name":"platforms","in":"query"}],"responses":{"200":{"description":"Stats","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"404":{"description":"Profile not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/post-analytics/{request_id}":{"get":{"security":[{"ApiKey":[]}],"tags":["Analytics"],"summary":"Stats for the posts of one publish request","parameters":[{"schema":{"type":"string"},"required":true,"name":"request_id","in":"path"},{"schema":{"type":"string"},"required":false,"name":"platform","in":"query"}],"responses":{"200":{"description":"Stats","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"request_id":{"type":"string"},"results":{"type":"object","additionalProperties":{}}},"required":["success","request_id","results"]}}}},"404":{"description":"Request not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/uploadposts/analyze-shorts":{"post":{"tags":["AI"],"summary":"Write captions for each network from a video","description":"Samples frames from the video (up to 100 MB, 5 minutes) and writes a title/caption per network within its limits. Uses one AI credit. Platforms: youtube, instagram, tiktok, facebook, x, threads, bluesky, linkedin, pinterest.","security":[{"ApiKey":[]}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"video":{"type":"string","description":"Video file or public https URL"},"platforms":{"type":"string","description":"Comma-separated; default youtube,instagram,tiktok"},"language":{"type":"string","description":"e.g. English, Urdu, es; detected when omitted"},"context":{"type":"string","description":"Your notes about the video: facts, names, the angle you want"}},"required":["video"]}}}},"responses":{"200":{"description":"Captions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Captions"}}}},"429":{"description":"No credits left","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"AI not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/upload_photos":{"post":{"tags":["Publishing"],"summary":"Publish one photo or a carousel","security":[{"ApiKey":[]}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UploadPhotosForm"}}}},"responses":{"200":{"description":"Per-platform results, or a request_id when it runs in the background","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"request_id":{"type":"string"}},"required":["success","request_id"],"additionalProperties":{}}}}},"202":{"description":"Scheduled","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"job_id":{"type":"string"},"request_id":{"type":"string"},"scheduled_date":{"type":"string"}},"required":["success","job_id","request_id","scheduled_date"]}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Monthly quota or rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/upload_text":{"post":{"tags":["Publishing"],"summary":"Publish a text-only post","description":"JSON or multipart.","security":[{"ApiKey":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadTextForm"}},"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UploadTextForm"}}}},"responses":{"200":{"description":"Per-platform results, or a request_id when it runs in the background","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"request_id":{"type":"string"}},"required":["success","request_id"],"additionalProperties":{}}}}},"202":{"description":"Scheduled","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"job_id":{"type":"string"},"request_id":{"type":"string"},"scheduled_date":{"type":"string"}},"required":["success","job_id","request_id","scheduled_date"]}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Monthly quota or rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/media/uploads":{"post":{"tags":["Publishing"],"summary":"Start a large upload straight to storage (files over 100 MB)","description":"Returns one signed PUT URL per part. PUT each part (bytes from (part_number - 1) × part_size) to its URL, keep the ETag header of each response, then POST /media/uploads/{media_id}/complete with {parts: [{part_number, etag}]}. The returned media_id works as video_media_id or photo_media_ids[]. Requests through app.reelspan.com are limited to 100 MB each, so use this for anything bigger.","security":[{"ApiKey":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["video","photo"]},"size_bytes":{"type":"integer","exclusiveMinimum":0},"filename":{"type":"string"}},"required":["kind","size_bytes"]}}}},"responses":{"200":{"description":"Part URLs","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"media_id":{"type":"string"},"part_size":{"type":"number"},"parts":{"type":"array","items":{"type":"object","properties":{"part_number":{"type":"number"},"url":{"type":"string"}},"required":["part_number","url"]}},"expires_in":{"type":"number"}},"required":["success","media_id","part_size","parts","expires_in"]}}}},"413":{"description":"Larger than the plan allows","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/media/uploads/{media_id}/complete":{"post":{"tags":["Publishing"],"summary":"Finish a large upload; the stored file is checked (size, type) before it can be used","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"media_id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"parts":{"type":"array","items":{"type":"object","properties":{"part_number":{"type":"integer"},"etag":{"type":"string"}},"required":["part_number","etag"]}}},"required":["parts"]}}}},"responses":{"200":{"description":"Stored","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"media_id":{"type":"string"},"kind":{"type":"string","enum":["video","photo"]},"content_type":{"type":"string"},"size_bytes":{"type":"number"},"duration_seconds":{"type":["number","null"]}},"required":["success","media_id","kind","content_type","size_bytes","duration_seconds"]}}}},"400":{"description":"Not the expected kind of file, or unsupported","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown or expired upload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/media/upload":{"post":{"tags":["Publishing"],"summary":"Upload a video or photo once, to publish or write captions from later","description":"Multipart field `file`. Use the returned media_id as video_media_id, photo_media_ids[] or <platform>_photo_media_ids[], or with adapt-captions.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","enum":["video","photo"],"default":"video"},"required":false,"name":"kind","in":"query"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","description":"The file (binary)"}},"required":["file"]}}}},"responses":{"200":{"description":"Stored","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"media_id":{"type":"string"},"kind":{"type":"string","enum":["video","photo"]},"content_type":{"type":"string"},"size_bytes":{"type":"number"},"duration_seconds":{"type":["number","null"]}},"required":["success","media_id","kind","content_type","size_bytes","duration_seconds"]}}}},"400":{"description":"Not a supported file","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Too large for the plan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/upload":{"post":{"tags":["Publishing"],"summary":"Publish a video to one or more networks","description":"Multipart upload. Waits up to 59 s for the result, then switches to background processing. Send `Idempotency-Key` to make retries safe.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":false,"name":"Idempotency-Key","in":"header"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UploadVideoForm"}}}},"responses":{"200":{"description":"Finished (per-platform results) or moved to the background (request_id)","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"request_id":{"type":"string"},"results":{"type":"object","additionalProperties":{"type":"object","properties":{"success":{"type":"boolean"},"url":{"type":["string","null"]},"error":{"type":"string"}},"required":["success"],"additionalProperties":{}}},"usage":{"type":"object","properties":{"count":{"type":"number"},"limit":{"type":["number","null"]},"last_reset":{"type":"string"}},"required":["count","limit","last_reset"]}},"required":["success","request_id","results","usage"]},{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"request_id":{"type":"string"},"total_platforms":{"type":"number"}},"required":["success","message","request_id","total_platforms"]}]}}}},"202":{"description":"Scheduled","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"job_id":{"type":"string"},"request_id":{"type":"string"},"scheduled_date":{"type":"string"}},"required":["success","job_id","request_id","scheduled_date"]}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Same Idempotency-Key still running","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"File too large for the plan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Monthly quota or rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{}}