{"openapi":"3.1.0","info":{"title":"uploadly API","version":"1.0.0","summary":"Send videos to your uploadly upload queue from any workflow.","description":"A real person uploads every video you send in YouTube Studio, on time; then we check it is live on the right channel. Create an API key in your uploadly dashboard → API keys and send it as `Authorization: Bearer upl_…`. Send a video with a link to its file (`video_url`) or upload it in parts (`file: \"upload\"`). Read its status, or set a webhook. Using Frontier? It is built in — no API needed. Limits: 60 requests a minute per key and 120 per account; 5000 a day per key and 10000 per account (UTC days). Poll a video at most every 5 minutes — better, set a webhook. Docs: https://uploadly.io/docs","contact":{"name":"uploadly","url":"https://uploadly.io/docs"}},"servers":[{"url":"https://uploadly.io/api/v1"}],"security":[{"bearer":[]}],"tags":[{"name":"Account"},{"name":"Videos"},{"name":"Files"},{"name":"Webhooks"}],"paths":{"/me":{"get":{"operationId":"getMe","tags":["Account"],"summary":"Your account, plan and limits","responses":{"200":{"description":"You","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}}}},"/channels":{"get":{"operationId":"listChannels","tags":["Account"],"summary":"Your channels and their publishing settings","responses":{"200":{"description":"Channels","content":{"application/json":{"schema":{"type":"object","properties":{"channels":{"type":"array","items":{"$ref":"#/components/schemas/Channel"}}},"required":["channels"]}}}},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}}}},"/videos":{"post":{"operationId":"createVideo","tags":["Videos"],"summary":"Send a video to the upload queue","description":"With `video_url` we copy the file in the background (status `fetching_file`, then `waiting`). With `file: \"upload\"` the answer has `upload.parts_url`: PUT the parts, then POST `upload.complete_url`. The same `external_id` with the same fields returns the same video (200, `Idempotent-Replayed: true`) — safe to retry; with other fields it is a 409 `idempotency_conflict` (nothing changes). Without `publish` the video takes the channel’s next free slot at its publish time, in its style (scheduled, or made public by hand inside its window). A scheduled time must be at least 2 h ahead. A file that arrives too late for its time moves the video (`publish.moved`, webhook `video.moved`): a channel slot to the next free one, a time of yours that is gone to “as soon as possible”. At most 10 videos waiting for parts and 30 being copied at once (429 `too_many_open_uploads`). The file must be a video (checked by its first bytes).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoCreate"},"example":{"channel":"@deepseafiles","title":"The Deepest Wreck Ever Found","description":"In 2019…","tags":["ocean","shipwreck"],"thumbnails":["https://files.example.com/thumb-a.jpg","https://files.example.com/thumb-b.jpg"],"video_url":"https://files.example.com/final.mp4?X-Amz-Signature=…","publish":{"mode":"schedule","at":"2026-10-28T17:00:00","tz":"Europe/Prague"},"altered_content":true,"made_for_kids":false,"external_id":"airtable-rec42"}}}},"responses":{"200":{"description":"The same external_id again: the video that exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoCreated"}}},"headers":{"Idempotent-Replayed":{"schema":{"type":"string","enum":["true"]}}}},"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoCreated"},"example":{"id":"vid_3f9a1c2b7d4e5f60a1b2c3d4","external_id":"airtable-rec42","channel":{"id":12,"name":"Deep Sea Files","handle":"@deepseafiles"},"title":"The Deepest Wreck Ever Found","status":"scheduled","publish":{"mode":"schedule","at":"2026-10-28T16:00:00Z","tz":"Europe/Prague","window":null,"from_channel":false,"style_fixed":true,"deadline":"2026-10-28T14:00:00Z","late_file":false,"moved":null},"youtube_url":"https://youtu.be/dQw4w9WgXcQ","checked":null,"problem":null,"issues":[],"file":{"state":"ready","name":"video.mp4","size":734003200,"received":734003200},"thumbnails":[{"n":1,"state":"ready"}],"created":"2026-10-27T19:02:11Z","updated":"2026-10-28T09:41:00Z"}}},"headers":{"Location":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"409":{"$ref":"#/components/responses/E409"},"413":{"$ref":"#/components/responses/E413"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}}},"get":{"operationId":"listVideos","tags":["Videos"],"summary":"Your API videos, newest first","parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["fetching_file","waiting","uploading","scheduled","waiting_window","live","checked","problem","canceled"]}},{"name":"channel","in":"query","description":"Channel id, @handle or name.","schema":{"type":"string"}},{"name":"external_id","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"cursor","in":"query","description":"`next_cursor` of the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page","content":{"application/json":{"schema":{"type":"object","properties":{"videos":{"type":"array","items":{"$ref":"#/components/schemas/Video"}},"next_cursor":{"type":["string","null"]}},"required":["videos","next_cursor"]}}}},"401":{"$ref":"#/components/responses/E401"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}}}},"/videos/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"The video id (vid_…).","schema":{"type":"string","example":"vid_3f9a1c2b7d4e5f60a1b2c3d4"}}],"get":{"operationId":"getVideo","tags":["Videos"],"summary":"One video: status, publish time, YouTube link, the check","responses":{"200":{"description":"The video","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Video"},"example":{"id":"vid_3f9a1c2b7d4e5f60a1b2c3d4","external_id":"airtable-rec42","channel":{"id":12,"name":"Deep Sea Files","handle":"@deepseafiles"},"title":"The Deepest Wreck Ever Found","status":"scheduled","publish":{"mode":"schedule","at":"2026-10-28T16:00:00Z","tz":"Europe/Prague","window":null,"from_channel":false,"style_fixed":true,"deadline":"2026-10-28T14:00:00Z","late_file":false,"moved":null},"youtube_url":"https://youtu.be/dQw4w9WgXcQ","checked":null,"problem":null,"issues":[],"file":{"state":"ready","name":"video.mp4","size":734003200,"received":734003200},"thumbnails":[{"n":1,"state":"ready"}],"created":"2026-10-27T19:02:11Z","updated":"2026-10-28T09:41:00Z"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}}},"delete":{"operationId":"cancelVideo","tags":["Videos"],"summary":"Cancel a video an uploader has not started yet","description":"Its files are deleted. Once an uploader started it: 409.","responses":{"200":{"description":"Canceled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Video"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"429":{"$ref":"#/components/responses/E429"}}}},"/videos/{id}/parts/{n}":{"parameters":[{"name":"id","in":"path","required":true,"description":"The video id (vid_…).","schema":{"type":"string","example":"vid_3f9a1c2b7d4e5f60a1b2c3d4"}},{"name":"n","in":"path","required":true,"schema":{"type":"integer","minimum":1,"maximum":10000}}],"put":{"operationId":"uploadPart","tags":["Files"],"summary":"Upload one part of the file (file: \"upload\")","description":"Raw bytes with Content-Length. At most 99614720 bytes (95 MB) a part; every part but the last the same size and at least 5 MiB. Parts may go in parallel and be sent again. Use the address in `upload.parts_url`.","requestBody":{"required":true,"content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"Stored","content":{"application/json":{"schema":{"type":"object","properties":{"part":{"type":"integer"},"size":{"type":"integer"},"etag":{"type":"string"}},"required":["part","size","etag"]}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"411":{"$ref":"#/components/responses/E411"},"413":{"$ref":"#/components/responses/E413"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}}}},"/videos/{id}/complete":{"parameters":[{"name":"id","in":"path","required":true,"description":"The video id (vid_…).","schema":{"type":"string","example":"vid_3f9a1c2b7d4e5f60a1b2c3d4"}}],"post":{"operationId":"completeUpload","tags":["Files"],"summary":"All parts are up: put the file together","description":"Then the video joins the queue (status waiting) — once its thumbnails are in too.","responses":{"200":{"description":"The video","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Video"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}}}},"/videos/{id}/thumbnails/{n}":{"parameters":[{"name":"id","in":"path","required":true,"description":"The video id (vid_…).","schema":{"type":"string","example":"vid_3f9a1c2b7d4e5f60a1b2c3d4"}},{"name":"n","in":"path","required":true,"schema":{"type":"integer","minimum":1,"maximum":3}}],"put":{"operationId":"uploadThumbnail","tags":["Files"],"summary":"Upload or replace thumbnail 1–3 (JPG, PNG or WebP, ≤ 2 MB)","description":"Raw image bytes. Allowed until an uploader starts the video. 2 or 3 thumbnails = YouTube’s Test & compare.","requestBody":{"required":true,"content":{"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"Stored","content":{"application/json":{"schema":{"type":"object","properties":{"thumbnail":{"type":"integer"},"size":{"type":"integer"},"name":{"type":"string"},"video":{"$ref":"#/components/schemas/Video"}}}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"413":{"$ref":"#/components/responses/E413"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}}}},"/videos/{id}/retry":{"parameters":[{"name":"id","in":"path","required":true,"description":"The video id (vid_…).","schema":{"type":"string","example":"vid_3f9a1c2b7d4e5f60a1b2c3d4"}}],"post":{"operationId":"retryVideoFile","tags":["Files"],"summary":"Copy the file again after a link problem — optionally from new links","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"video_url":{"type":"string","format":"uri"},"thumbnails":{"type":"array","items":{"type":"string"},"maxItems":3}}}}}},"responses":{"200":{"description":"Copying again","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Video"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}}}},"/webhook":{"get":{"operationId":"getWebhook","tags":["Webhooks"],"summary":"Your webhook","responses":{"200":{"description":"The webhook","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}}},"put":{"operationId":"setWebhook","tags":["Webhooks"],"summary":"Set the webhook URL — a new signing secret, shown once","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"https only"}},"required":["url"]},"example":{"url":"https://n8n.example.com/webhook/uploadly"}}}},"responses":{"200":{"description":"Set","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"secret":{"type":"string","description":"whsec_… — keep it; it is not shown again"},"events":{"type":"array","items":{"type":"string"}},"shown_once":{"type":"boolean"}},"required":["url","secret"]}}}},"401":{"$ref":"#/components/responses/E401"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}}},"delete":{"operationId":"deleteWebhook","tags":["Webhooks"],"summary":"Remove the webhook","responses":{"200":{"description":"Removed","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}}}},"/webhook/test":{"post":{"operationId":"testWebhook","tags":["Webhooks"],"summary":"Send a signed `ping` event now","responses":{"200":{"description":"What your server answered","content":{"application/json":{"schema":{"type":"object","properties":{"delivered":{"type":"boolean"},"code":{"type":["integer","null"]},"error":{"type":["string","null"]},"delivery":{"$ref":"#/components/schemas/Delivery"}}}}}},"401":{"$ref":"#/components/responses/E401"},"409":{"$ref":"#/components/responses/E409"},"429":{"$ref":"#/components/responses/E429"}}}},"/webhook/deliveries":{"get":{"operationId":"listWebhookDeliveries","tags":["Webhooks"],"summary":"The delivery log (30 days)","parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["pending","delivered","failed"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"responses":{"200":{"description":"Deliveries","content":{"application/json":{"schema":{"type":"object","properties":{"deliveries":{"type":"array","items":{"$ref":"#/components/schemas/Delivery"}}}}}}},"401":{"$ref":"#/components/responses/E401"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}}}},"/openapi.json":{"get":{"operationId":"getOpenApi","tags":["Account"],"summary":"This document","security":[],"responses":{"200":{"description":"OpenAPI 3.1"}}}}},"webhooks":{"video.scheduled":{"post":{"summary":"A video reached scheduled","description":"Signed: `Uploadly-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" with your secret>`. Answer 2xx within 10 s; otherwise we try again after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h and 24 h.","parameters":[{"name":"Uploadly-Signature","in":"header","required":true,"schema":{"type":"string"}},{"name":"Uploadly-Event","in":"header","schema":{"type":"string"}},{"name":"Uploadly-Delivery","in":"header","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Received"}}}},"video.live":{"post":{"summary":"A video reached live","description":"Signed: `Uploadly-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" with your secret>`. Answer 2xx within 10 s; otherwise we try again after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h and 24 h.","parameters":[{"name":"Uploadly-Signature","in":"header","required":true,"schema":{"type":"string"}},{"name":"Uploadly-Event","in":"header","schema":{"type":"string"}},{"name":"Uploadly-Delivery","in":"header","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Received"}}}},"video.checked":{"post":{"summary":"A video reached checked","description":"Signed: `Uploadly-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" with your secret>`. Answer 2xx within 10 s; otherwise we try again after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h and 24 h.","parameters":[{"name":"Uploadly-Signature","in":"header","required":true,"schema":{"type":"string"}},{"name":"Uploadly-Event","in":"header","schema":{"type":"string"}},{"name":"Uploadly-Delivery","in":"header","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Received"}}}},"video.problem":{"post":{"summary":"A video reached problem","description":"Signed: `Uploadly-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" with your secret>`. Answer 2xx within 10 s; otherwise we try again after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h and 24 h.","parameters":[{"name":"Uploadly-Signature","in":"header","required":true,"schema":{"type":"string"}},{"name":"Uploadly-Event","in":"header","schema":{"type":"string"}},{"name":"Uploadly-Delivery","in":"header","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Received"}}}},"video.canceled":{"post":{"summary":"A video reached canceled","description":"Signed: `Uploadly-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" with your secret>`. Answer 2xx within 10 s; otherwise we try again after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h and 24 h.","parameters":[{"name":"Uploadly-Signature","in":"header","required":true,"schema":{"type":"string"}},{"name":"Uploadly-Event","in":"header","schema":{"type":"string"}},{"name":"Uploadly-Delivery","in":"header","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Received"}}}},"video.moved":{"post":{"summary":"A late file moved the video’s time (see data.video.publish.moved)","description":"Signed: `Uploadly-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" with your secret>`. Answer 2xx within 10 s; otherwise we try again after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h and 24 h.","parameters":[{"name":"Uploadly-Signature","in":"header","required":true,"schema":{"type":"string"}},{"name":"Uploadly-Event","in":"header","schema":{"type":"string"}},{"name":"Uploadly-Delivery","in":"header","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Received"}}}},"ping":{"post":{"summary":"Sent by POST /webhook/test","description":"Signed: `Uploadly-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" with your secret>`. Answer 2xx within 10 s; otherwise we try again after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h and 24 h.","parameters":[{"name":"Uploadly-Signature","in":"header","required":true,"schema":{"type":"string"}},{"name":"Uploadly-Event","in":"header","schema":{"type":"string"}},{"name":"Uploadly-Delivery","in":"header","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Received"}}}}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","bearerFormat":"upl_…","description":"Create a key in your dashboard → API keys. It is shown once."}},"responses":{"E400":{"description":"Not JSON","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E401":{"description":"No key, or an unknown / revoked one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E403":{"description":"Your service is paused or canceled (`service_off`): reading and removing still work","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E409":{"description":"Not in this state (e.g. an uploader already started it), or `idempotency_conflict`: that external_id is another video (in `video`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E411":{"description":"Content-Length missing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E413":{"description":"Too big (a part, a thumbnail, the video, a JSON body over its limit)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E422":{"description":"Validation failed — `fields` says which and why; an unknown channel lists `channels`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E429":{"description":"`rate_limited` (over 60 a minute per key / 120 per account), `daily_quota` (over 5000 / 10000 a day) or `too_many_open_uploads` — see Retry-After","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"fields":{"type":"object","additionalProperties":{"type":"string"}},"channels":{"type":"array","items":{"$ref":"#/components/schemas/ChannelBrief"}},"retry_after":{"type":"integer"},"video":{"$ref":"#/components/schemas/Video"}},"required":["error","code"]},"Me":{"type":"object","properties":{"client":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"},"tz":{"type":"string"},"member":{"type":"boolean"}}},"plan":{"type":"object","properties":{"slots":{"type":"integer"},"slots_used":{"type":"integer"},"price_per_slot_usd":{"type":"number","description":"Per slot a month, after the volume discount."},"discount_pct":{"type":"integer","description":"Volume discount on every slot: 10 from 5 slots, 20 from 10."},"total_usd":{"type":"number","description":"A month for slots_used."},"note":{"type":"string"}}},"channels":{"type":"integer"},"webhook":{"type":["string","null"]},"key":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"prefix":{"type":"string"}}},"limits":{"type":"object","additionalProperties":{"type":"integer"}},"now":{"type":"string","format":"date-time"}}},"ChannelBrief":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"handle":{"type":["string","null"]}}},"Channel":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"handle":{"type":["string","null"]},"yt_id":{"type":["string","null"],"description":"UC…"},"publish_style":{"type":"string","enum":["schedule","by_hand"],"description":"schedule: scheduled in Studio. by_hand: uploaded as Private and made public by hand inside the window."},"publish_time":{"type":"string","example":"17:00"},"window":{"type":"object","properties":{"from":{"type":"string","example":"12:00"},"to":{"type":"string","example":"17:00"}},"description":"The by-hand window around a video’s time (clock times in tz)."},"tz":{"type":"string","example":"Europe/Prague"},"per_day":{"type":"integer"},"access":{"type":"string","enum":["invite","invited","ok","lost"]},"playlist":{"type":["string","null"]}}},"Publish":{"type":"object","description":"Leave it out: the channel’s next free slot, in the channel’s style.","properties":{"mode":{"type":"string","enum":["schedule","by_hand","now","private","unlisted"],"description":"schedule = scheduled in Studio for `at`; by_hand = private, made public by hand inside the channel’s window around `at`; now = public once uploaded; private; unlisted. Left out: the channel’s style."},"at":{"oneOf":[{"type":"string","description":"ISO 8601 (with Z / an offset, or without = in tz), a date alone (= the channel’s publish time that day), or HH:MM (= the next one; scheduled: the next one at least 2 h away)"},{"type":"integer","description":"unix seconds"}],"description":"Scheduled: at least 2 h ahead (it must be in Studio 2 h before). By hand: its window must close at least 30 min from now."},"tz":{"type":"string","description":"IANA zone for an `at` without an offset. Default: the channel’s."}}},"VideoCreate":{"type":"object","required":["title"],"properties":{"channel":{"oneOf":[{"type":"integer"},{"type":"string"}],"description":"Channel id, @handle, UC… id or name. Optional when you have one channel."},"title":{"type":"string","maxLength":100},"description":{"type":"string","maxLength":5000},"tags":{"oneOf":[{"type":"array","items":{"type":"string"}},{"type":"string","description":"comma-separated"}],"description":"500 characters together at most"},"thumbnails":{"type":"array","maxItems":3,"items":{"type":"string","description":"https link, or \"upload\" (then PUT /videos/{id}/thumbnails/{n})"},"description":"2–3 = Test & compare"},"video_url":{"type":"string","format":"uri","description":"A direct https link to the file (S3 / R2 presigned, Dropbox ?dl=1, Google Drive direct download…) on a public host. It must send Content-Length; files over 100 MB are copied in byte ranges, and over 1 GB the link MUST answer them. Up to 5 redirects (https only)."},"file":{"type":"string","enum":["upload"],"description":"Instead of video_url: send the file in parts."},"file_name":{"type":"string","description":"With file: \"upload\" — its extension (.mp4, .mov…) is kept."},"publish":{"$ref":"#/components/schemas/Publish"},"playlist":{"type":"string","maxLength":150},"made_for_kids":{"type":"boolean","default":false},"altered_content":{"type":"boolean","default":false,"description":"YouTube’s “altered or synthetic content” (AI) label"},"category":{"type":"string","maxLength":60},"language":{"type":"string","maxLength":40},"pinned_comment":{"type":"string","maxLength":4000},"notes":{"type":"string","maxLength":2000,"description":"For your uploader"},"external_id":{"type":"string","maxLength":200,"description":"Your own id: the same one again returns the same video (idempotency)."}}},"Video":{"type":"object","required":["id","status","title","channel","publish","file","created","updated"],"properties":{"id":{"type":"string"},"external_id":{"type":["string","null"]},"channel":{"$ref":"#/components/schemas/ChannelBrief"},"title":{"type":"string"},"status":{"type":"string","enum":["fetching_file","waiting","uploading","scheduled","waiting_window","live","checked","problem","canceled"],"description":"fetching_file → waiting → uploading → scheduled / waiting_window / live → checked; or problem / canceled"},"publish":{"type":"object","properties":{"mode":{"type":"string","enum":["schedule","by_hand","now","private","unlisted"]},"at":{"type":["string","null"],"format":"date-time"},"tz":{"type":"string"},"window":{"type":["object","null"],"properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"}}},"from_channel":{"type":"boolean","description":"The time was the channel’s next free slot"},"style_fixed":{"type":"boolean"},"deadline":{"type":["string","null"],"format":"date-time","description":"By when the uploader must be done"},"late_file":{"type":"boolean","description":"The file came after the uploader’s deadline (or less than 30 min before it)"},"moved":{"type":["object","null"],"description":"A late file moved the time: a channel slot to the next free one; a time of yours that was gone to “as soon as possible” (mode now, `to` null)","properties":{"from":{"type":"string","format":"date-time"},"to":{"type":["string","null"],"format":"date-time"},"reason":{"type":"string","enum":["late_file"]},"message":{"type":"string"}}}}},"youtube_url":{"type":["string","null"]},"checked":{"type":["object","null"],"description":"The last automatic check on YouTube","properties":{"public":{"type":"boolean"},"channel_ok":{"type":"boolean"},"title_ok":{"type":"boolean"},"public_at":{"type":["string","null"],"format":"date-time"},"at":{"type":"string","format":"date-time"}}},"problem":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":"string"}}},"issues":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}},"file":{"type":"object","properties":{"state":{"type":"string","enum":["copying","awaiting_parts","awaiting_thumbnails","ready","failed","removed"]},"name":{"type":"string"},"size":{"type":["integer","null"]},"received":{"type":"integer"}}},"thumbnails":{"type":"array","items":{"type":"object","properties":{"n":{"type":"integer"},"state":{"type":"string","enum":["copying","awaiting_upload","ready"]}}}},"created":{"type":"string","format":"date-time"},"updated":{"type":"string","format":"date-time"}}},"VideoCreated":{"allOf":[{"$ref":"#/components/schemas/Video"},{"type":"object","properties":{"upload":{"type":"object","description":"Only while it waits for the file / thumbnails from you","properties":{"parts_url":{"type":"string","example":"https://uploadly.io/api/v1/videos/vid_…/parts/{n}"},"complete_url":{"type":"string"},"max_part_bytes":{"type":"integer","example":99614720},"min_part_bytes":{"type":"integer"},"thumbnails_url":{"type":"string"},"thumbnails":{"type":"array","items":{"type":"integer"}},"thumbnail_max_bytes":{"type":"integer","example":2097152},"how":{"type":"string"}}},"warnings":{"type":"array","items":{"type":"string"}},"idempotent_replay":{"type":"boolean"}}}]},"Webhook":{"type":"object","properties":{"url":{"type":["string","null"]},"events":{"type":"array","items":{"type":"string","enum":["video.scheduled","video.live","video.checked","video.problem","video.canceled","video.moved"]}},"created":{"type":["string","null"]},"updated":{"type":["string","null"]}}},"Delivery":{"type":"object","properties":{"id":{"type":"string","description":"The event id"},"event":{"type":"string"},"video_id":{"type":["string","null"]},"status":{"type":"string","enum":["pending","delivered","failed"]},"attempts":{"type":"integer"},"last_code":{"type":["integer","null"]},"last_error":{"type":["string","null"]},"created":{"type":"string","format":"date-time"},"delivered_at":{"type":["string","null"]},"next_try":{"type":["string","null"]}}},"WebhookEvent":{"type":"object","required":["id","type","created","data"],"properties":{"id":{"type":"string","example":"evt_…"},"type":{"type":"string","enum":["video.scheduled","video.live","video.checked","video.problem","video.canceled","video.moved","ping"]},"created":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"video":{"oneOf":[{"$ref":"#/components/schemas/Video"},{"type":"null"}]},"message":{"type":"string"}}}}}}}}