{"openapi":"3.1.0","info":{"title":"Scrub API","version":"1","description":"Every Scrub tool over HTTP, the same tools as Scrub over MCP. Send a key from Account as Authorization: Bearer. POST /v1/tools/quote prices work before it runs, free. A job that takes time answers at once with its job_id and status running; ask POST /v1/tools/job_status until its status is succeeded, or failed, refused or cancelled, each answered 200 with what happened and what was charged."},"servers":[{"url":"https://app.scrub.app"}],"components":{"securitySchemes":{"key":{"type":"http","scheme":"bearer","description":"An API key from Account, or an OAuth access token"}},"schemas":{"Result":{"type":"object","properties":{"ok":{"type":"boolean","const":true},"text":{"type":"string","description":"What happened, in words, as an AI is told it"},"result":{"type":"object","description":"The same as data: a job_id and status for work, a price for a quote"}},"required":["ok","text"]},"Error":{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","description":"Why, in words"}},"required":["ok","error"]}}},"tags":[{"name":"Work","description":"Actions and tools: the work Scrub does, priced by the work"},{"name":"Prices and jobs","description":"Quote before, follow a job, change a finished one"},{"name":"Files","description":"Put files in, find them, look at them, delete them"},{"name":"Corrections","description":"Correct a result by hand, free"},{"name":"Drafts","description":"What is set on a page and not yet run, kept as it is made"},{"name":"Flows","description":"Tools and actions chained on the canvas, kept with each version. A flow runs at /v1/tools/<its name>, as a tool does."},{"name":"Brand Kits","description":"A workspace's look, kept by name: a timeline's own parts, put on a video by writing them into its timeline."},{"name":"About","description":"What this API serves"}],"paths":{"/v1/tools":{"get":{"operationId":"list_tools","summary":"List the tools","description":"Every tool this API serves, with its input schema. Free; no key needed. Sent with a key, the key's workspace's flows too.","tags":["About"],"security":[{},{"key":[]}],"responses":{"200":{"description":"The tools","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/v1/tools/add_captions":{"post":{"operationId":"add_captions","summary":"Caption a video","description":"Captions a video from the video alone, as subtitles burned into the picture, at most two lines and seven seconds each. Give a transcription to skip transcribing.\n\nTakes src (file), transcript (file, optional). Returns video, preview, edl (the captions as drawn, each with its words, times, place and style, and the source they were drawn on). One job: transcribing, then making captions, then burning in captions. Given transcript, it skips transcribing.\n\n$0.10 a minute of video + $0.15 per 10 minutes of audio, up to 60 minutes. quote gives its exact price.\n\nAfterwards, change the result with adjust on the job of the step that made it, listed in the result.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"src":{"type":"string","description":"A file_id from create_upload, accepting video/*, up to 2 GB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result."},"transcript":{"type":"string","description":"A file_id from create_upload, accepting application/vnd.scrub.transcript+json, application/json, up to 16 MB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result."},"position":{"description":"Where the captions sit.","type":"string","enum":["lower_third","centre","top_left"],"default":"lower_third"},"style":{"description":"How the captions look. clean: White, heavy, a few words at a time. Each word lights up as it is said. pill: The word being said sits in a white pill, in black. box: The phrase on a dark rounded box, for busy footage. bold: Heavy words that pop in as they are said; the word being said grows. subtitles: One or two full lines, smaller, without movement: for talks and wide videos.","type":"string","enum":["clean","pill","box","bold","subtitles"],"default":"clean"},"font":{"description":"The font the captions are set in. Inter Tight: Tight and even; every caption style's face. Inter: The plainest, most legible sans; explainers and data. Manrope: Calm, geometric and modern. Archivo: Sturdy grotesque with real weight; news and how-tos. Montserrat: The face most short-form captions are set in. Poppins: Round geometric sans; friendly brands and lifestyle. Figtree: Clean and warm, a little softer than Inter. Bricolage Grotesque: Quirky editorial sans. Rubik: Slightly rounded corners; playful but tidy. Bebas Neue: Tall capitals; titles, numbers and sport. Anton: Heavy, narrow capitals; the loudest hook text. Oswald: Condensed, with weights; lists and labels. League Gothic: Classic condensed gothic; posters and film titles. Fraunces: Soft, old-style serif; warm stories. Playfair Display: High-contrast serif; elegant titles. Instrument Serif: Narrow editorial serif. DM Serif Display: Bold display serif; quotes and headlines. PT Serif: Classic text serif with italics; reports, history and quotes. Caveat: Quick handwriting; notes and asides. Bangers: Comic-book capitals; reactions and gaming. Luckiest Guy: Fat cartoon capitals; kids, gaming and hooks. JetBrains Mono: Monospace; code, terminals and numbers that line up.","type":"string","enum":["Inter Tight","Inter","Manrope","Archivo","Montserrat","Poppins","Figtree","Bricolage Grotesque","Rubik","Bebas Neue","Anton","Oswald","League Gothic","Fraunces","Playfair Display","Instrument Serif","DM Serif Display","PT Serif","Caveat","Bangers","Luckiest Guy","JetBrains Mono"],"default":"Inter Tight"},"size":{"description":"The captions' type size, in pixels on a frame whose shorter side is 1080; larger shows fewer words at a time.","type":"number","minimum":16,"maximum":400,"default":72},"rows":{"description":"How many lines a caption runs to; as many words show at once as fit.","type":"number","minimum":1,"maximum":2,"default":1},"case":{"description":"Capital letters as said, all capitals, or all lower case.","type":"string","enum":["as_said","capitals","lower_case"],"default":"as_said"},"weight":{"description":"How heavy its letters are; the nearest weight its font has is drawn. style: its style's own","type":"string","enum":["style","100","200","300","400","500","600","700","800","900"],"default":"style"},"ahead":{"description":"How the words of a caption not said yet look, in a style that shows a caption's words together. style: as its style shows them faded: faint until each is said full: as clear as the word being said","type":"string","enum":["style","faded","full"],"default":"style"},"in":{"description":"How each caption comes in. style: the move its style has none: just there fade: comes up from nothing rise: lifts into place pop: springs up with a little overshoot","type":"string","enum":["style","none","fade","rise","pop"],"default":"style"},"out":{"description":"How each caption goes as the next comes. fade: a quick fade as the next comes none: just gone","type":"string","enum":["fade","none"],"default":"fade"}},"required":["src"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/make_a_loop":{"post":{"operationId":"make_a_loop","summary":"Make a loop","description":"Makes a short video that loops: it plays on repeat with no jump, for a background or a post. From a few words, or from an image, which is the clip's first and last frame. The movement has to come back round, like waves, a fire, a flag in the wind or birds circling; something crossing the picture one way cannot loop. 8 seconds at most, without sound.\n\nTakes image (file, optional). Returns video. One job: making the image, then filming, then finding the loop. Given image, it skips making the image.\n\n$0.21 a second of video + $0.07 an image, up to 8 seconds. quote gives its exact price.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"image":{"type":"string","description":"A file_id from create_upload, accepting image/jpeg, image/png, image/webp, up to 20 MB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result."},"prompt":{"description":"What is in the picture and what moves, in a sentence or a few, such as birds circling over a loch at dusk; English works best. With an image, what moves in it.","type":"string"},"model":{"description":"The model that films it, each at its own price.","type":"string","enum":["Veo 3.1 Fast","Veo 3.1"],"default":"Veo 3.1 Fast"},"aspect_ratio":{"description":"Its aspect ratio, width to height.","type":"string","enum":["16:9","9:16"],"default":"16:9"}},"required":["prompt"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/make_narrated_video":{"post":{"operationId":"make_narrated_video","summary":"Make a narrated video","description":"A narrated video, such as an explainer or a short with a voiceover, from its timeline. Images and music it describes and has not got are made, the music as long as the video, the script is voiced, and the images, words on screen, captions, logo, sounds and music are drawn into one video, each at its moment. To change a finished video, run it again on the timeline its voice step returned, with the change made: images, music and lines already made are kept and not charged again, so a new image costs only the video and a changed line adds only its voice.\n\nTakes timeline (a video's timeline). Returns video, preview, captions (every caption as it is shown, from when it shows until it goes, as an SRT file. None when the video has no captions). One job: making the images, then making the music, then voicing the script, then drawing the video.\n\n$0.10 a minute of video + $0.01 per 12 seconds of speech + $0.08 per 30 seconds of music, at least $0.10, at most $0.30 + $0.07 an image, up to 3 minutes. quote gives its exact price.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"timeline":{"description":"The video, scene by scene, with its look; or a script, whose lines become its scenes: text, or one already voiced, as given back voiced, each voiced line kept as it was voiced and not voiced again. A timeline is {version: 2, title?, aspect_ratios: [9:16, 1:1, 4:5, 16:9], brand?: {back, text, accent: colours like #1c1c1c (the accent colours a caption style's key or said word; leave it out to keep captions black and white), font: the font of words on screen that name none, one of Inter Tight, Inter, Manrope, Archivo, Montserrat, Poppins, Figtree, Bricolage Grotesque, Rubik, Bebas Neue, Anton, Oswald, League Gothic, Fraunces, Playfair Display, Instrument Serif, DM Serif Display, PT Serif, Caveat, Bangers, Luckiest Guy, JetBrains Mono}, voice?: {name: one of Achernar (soft, female), Achird (friendly, male), Algenib (gravelly, male), Algieba (smooth, male), Alnilam (firm, male), Aoede (breezy, female), Autonoe (bright, female), Callirrhoe (easy-going, female), Charon (informative, male), Despina (smooth, female), Enceladus (breathy, male), Erinome (clear, female), Fenrir (excitable, male), Gacrux (mature, female), Iapetus (clear, male), Kore (firm, female), Laomedeia (upbeat, female), Leda (youthful, female), Orus (firm, male), Pulcherrima (forward, female), Puck (upbeat, male), Rasalgethi (informative, male), Sadachbia (lively, male), Sadaltager (knowledgeable, male), Schedar (even, male), Sulafat (warm, female), Umbriel (easy-going, male), Vindemiatrix (gentle, female), Zephyr (bright, female), Zubenelgenubi (casual, male)}, captions?: {style: clean (Clean: White, heavy, a few words at a time. Each word lights up as it is said.), pill (Pill: The word being said sits in a white pill, in black.), box (Box: The phrase on a dark rounded box, for busy footage.), bold (Bold: Heavy words that pop in as they are said; the word being said grows.), subtitles (Subtitles: One or two full lines, smaller, without movement: for talks and wide videos.) or off; size?: a type size, 16 to 400, pixels on a frame whose shorter side is 1080 (about 72 reads like a phone app's captions; larger means fewer words at a time); font?: one of the fonts below (Inter Tight when left out); rows?: 1 or 2 lines a caption runs to (1 when left out); width?: how wide a caption may run, as a share of the frame's shorter side, 0.2 to 3; colour?: a colour like #ffffff; said_colour?: the word being said in Pill, on its pill (near-black when left out); weight?: 100 to 900, the nearest its font has (its style's when left out); ahead?: the words not said yet, style (As its style: as its style shows them), faded (Faded: faint until each is said), full (Full: as clear as the word being said) (style when left out; none to come in a style that shows each word as it is said); outline?: false for none, or {colour?, width?: 0 to 30, percent of the type size}; shadow?: false for none, or {colour?, opacity?: 0 to 100 percent, blur?: 0 to 100 and distance?: 0 to 50, percent of the type size, the shadow dropped straight down} (the style's own when left out); in?: style (As its style: the move its style has), none (None: just there), fade (Fade: comes up from nothing), rise (Rise: lifts into place), pop (Pop: springs up with a little overshoot) (style when left out); out?: fade (Fade out: a quick fade as the next comes), none (None: just gone) (fade when left out); with a size, each caption is as many words as fit its width in its rows, never ending on a weak word; case: as_said, capitals, lower_case; place?: {x, y}: where every caption sits, its middle as shares of the frame's width and height, 0.05 to 0.95 (above the bottom of the safe area when left out); lines?: [{from, to: the first and last word of one scene's line it shows, each {scene: id, word, nth?}; text?: what it shows instead of those words, such as 58% for fifty-eight percent, at most 120 characters; place?: {x, y} for this one; hide?: true to show nothing for it; hold?: true to stay on screen until the next caption; inline?: true for text shown among the words around it, in their caption, such as a figure for words said, never a caption of its own}]: captions set by hand, none overlapping; every other caption is made from the words said, a few at a time}, pauses?: {longest?: seconds, 0 to 5, that every longer pause plays; at?: [{after: {scene: id, word, nth?}, seconds: 0 to 10}]: a pause after that word set by hand, made where there was none; or {before: {scene: id, word}, seconds} for the quiet before the first word of a line with nothing said before it, from its scene's start}: a pause is a gap of a quarter second or more between two words the voice said, or before a line's first word or after its last where nothing is said before or after it; a line not voiced yet has only the pauses set on it by hand, which play exactly as set once it is voiced; longest leaves the quiet before a first word and after a last word as voiced; shortened, lengthened or removed, the video is that much shorter or longer and everything after it moves with its words, and nothing is voiced again, transition?: cut, blur, fade, push, zoom between images (cut, none, when left out), look?: natural, mono, film, crisp over the images, progress?: true for a thin bar showing how much is left, safe?: {area: usual (TikTok, Reels and Shorts: inside the lines captions and text sit on, clear of what the apps put over a video), tiktok (TikTok: clear of TikTok's buttons, name and caption), reels (Instagram Reels: clear of Instagram's buttons, name and caption), shorts (YouTube Shorts: clear of YouTube's buttons, name and caption), even (Even margin: the same distance from every edge), none (None: only the frame's edges and middle) (usual when left out; TikTok, Reels and Shorts each in 9:16 only, the usual one in other shapes), margin?: for even, a share of the frame's shorter side, 0.01 to 0.25 (0.05 when left out)}: where nothing a person needs to read should sit, as placed gives it in each aspect ratio; keep text boxes, logos and captions inside it, music?: {prompt?: what it sounds like, its mood, instruments and pace, only when the person asks for music (made when it runs, as long as the video), src?: a file_id, from?: prompt when it was made from those words, volume 0 to 1}, scenes: [{id, line: what is said, duration: seconds, hold?: seconds it runs on after its line and its clips end, keys?: one or two words of the line, exactly as written, that carry its meaning}], images: [{id, at, until?, src?: a file_id, kind: image or video, motion: still, push, punch, zoom_in, zoom_out, pan_left, pan_right (still when left out; punch jumps closer on a key word), fit?: whole to show all of an image of another shape on a blurred copy of itself, prompt?: what it shows in a sentence or two (made from those words when it has no src), from?: prompt when it was made from them, make?: false to show the video's colours instead, box?: where it sits when not filling the frame, fades?: true for an image with an until to fade in and out (it is simply there when left out), turn?: degrees turned clockwise (-180 to 180), crop?: {left, top, right, bottom}: shares of the image trimmed from each side, 0 to 0.9, length?: a clip's own seconds (read from its file when a draft is saved), start?: seconds into a clip where it begins, to cut its beginning, to?: seconds into a clip where it stops, to cut it short, volume?: 0 to 1 and fade?: seconds for a clip's own sound}], words: [{id, value: the words shown, at most 200 characters, a new line where it breaks, at, until?, box: {x, y, w}: where the text box sits (a box as below; w is the width its words wrap at), font?: one of Inter Tight (Tight and even; every caption style's face.), Inter (The plainest, most legible sans; explainers and data.), Manrope (Calm, geometric and modern.), Archivo (Sturdy grotesque with real weight; news and how-tos.), Montserrat (The face most short-form captions are set in.), Poppins (Round geometric sans; friendly brands and lifestyle.), Figtree (Clean and warm, a little softer than Inter.), Bricolage Grotesque (Quirky editorial sans.), Rubik (Slightly rounded corners; playful but tidy.), Bebas Neue (Tall capitals; titles, numbers and sport.), Anton (Heavy, narrow capitals; the loudest hook text.), Oswald (Condensed, with weights; lists and labels.), League Gothic (Classic condensed gothic; posters and film titles.), Fraunces (Soft, old-style serif; warm stories.), Playfair Display (High-contrast serif; elegant titles.), Instrument Serif (Narrow editorial serif.), DM Serif Display (Bold display serif; quotes and headlines.), PT Serif (Classic text serif with italics; reports, history and quotes.), Caveat (Quick handwriting; notes and asides.), Bangers (Comic-book capitals; reactions and gaming.), Luckiest Guy (Fat cartoon capitals; kids, gaming and hooks.), JetBrains Mono (Monospace; code, terminals and numbers that line up.), weight?: 400 to 900 (the nearest the font has), italic?: true for its italics where it has them, size?: a type size, 16 to 400, pixels on a frame whose shorter side is 1080 (about 120 a title, 72 a line, 48 small print), colour?, align?: left, center, right, outline?: false for none, or {colour?, width?: 0 to 30, percent of the type size}; shadow?: false for none, or {colour?, opacity?: 0 to 100 percent, blur?: 0 to 100 and distance?: 0 to 50, percent of the type size, the shadow dropped straight down} (none and a soft shadow when left out; an outline may also be a colour alone), back?: a colour for a rounded box behind each line, in?: how it comes in, none (None: Just there.), fade (Fade: Comes up from nothing.), rise (Rise: Each word lifts into place.), slide (Slide: Slides in from the left.), pop (Pop: Springs up from small, with a little overshoot.), blur (Blur in: Each word sharpens out of a blur.), typewriter (Typewriter: Typed out, letter by letter.), wipe (Wipe: Revealed from left to right.), word_pop (Word by word: Words pop in one after another.), stomp (Stomp: Slams down from huge with a small shake.), highlighter (Highlighter: A marker swipes in behind the words.), letters (Letter cascade: Letters tumble in one by one.), count (Count up: Its numbers run up to their value.) (none when left out), out?: how it goes, none (None: Just gone.), fade (Fade out: Fades away.), sink (Sink: Each word drops away.), slide_out (Slide out: Slides off to the right.), pop_out (Pop out: Swells a touch, then shrinks to nothing.), blur_out (Blur out: Dissolves into a blur.), wipe_out (Wipe out: Wiped away from left to right.), backspace (Backspace: Deleted letter by letter from the end.) (none when left out)}]: text boxes, inside the safe area unless the person says where; words without a box are from before and sit at a place (top, middle, bottom) and come in by an animation (blur, rise, hook, pop, slide, fade, typewriter), sounds: [{id, src: a file_id, at, until?, volume 0 to 1, fade: seconds it fades in and out}]}. The script is said in one voice, scene after scene; a scene lasts its duration, at least as long as its line takes to say, and a scene with no line is a pause; a clip that begins in a scene, with no until or until the scene's end, plays from its start (or its first frame) to its own end (or its to) and the scene runs on until it does, then for its hold, and everything after moves along. A clip's sound plays, lowered while the voice speaks. Images, words and sounds each begin at their at and end at their until. A moment is {scene: id} (its start, or with end: true its end), {scene: id, word: one word of its line, nth?: 2 for its second time, end?: true when it has been said}, or {item: id of an image, words or sound, end?: true}, any of them with plus?: seconds after it (in tenths). An image with no until lasts until the next image with no until begins; a clip never shows past its own end (or its to); words on screen last for the scene they begin in; a sound lasts its own length. Where images show at the same time, a later one in images is drawn on top of an earlier one; where none shows, the video's colours. A logo, or anything else that stays on screen, is an image with a box from the first scene's start until the last scene's end, small (w about 0.18) in a top corner inside the safe area, unless the person says where. A box is {x, y, w}: its middle as shares of the frame's width and height (0.5, 0.5 is the middle; -1 to 2, so it can hang over an edge) and its width as a share of the frame's shorter side (0.02 to 10); its height follows its own shape, and what is outside the frame is not shown. Ids are short names, each used once. files?: [file_id, …]: files kept with the video and not yet placed in it, so its Media shows them when it is opened again. Files are file_ids from this workspace.","type":"object"},"aspect_ratio":{"description":"The aspect ratio to make it in, width to height.","type":"string","enum":["9:16","1:1","4:5","16:9"],"default":"9:16"},"part":{"type":"string","enum":["voice","images","music"],"description":"Only this part, made now at its own price, to see or hear it before the rest: voice (Voice a script), images (Generate an image), music (Generate music). The settings come back with it in place and the next part is offered. Left out, all of it is made."}},"required":["timeline"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/make_short":{"post":{"operationId":"make_short","summary":"Make a short from a video","description":"A finished short from a stretch of a longer recording (a podcast, a webinar, a talk), its video or its audio alone, from the draft Plan the cutaways lays out: the speaker upright, or from audio a picture the whole way through, captions from what is said, the hook it opens on, and the cutaways on its key points made, then drawn into one video. A cutaway left empty shows the speaker. To change a finished short, run it again on its draft with the change made: cutaways already made are kept and not charged again.\n\nTakes timeline (a video's timeline). Returns video, preview, captions (every caption as it is shown, from when it shows until it goes, as an SRT file. None when the video has no captions). One job: making the cutaways, then drawing the video.\n\n$0.10 a minute of video + $0.07 an image, up to 3 minutes. quote gives its exact price.\n\nFor a screen recording, no face on screen (said as screen recording, screen share, screen-share, screencast, shared screen, no face), run plan_cutaways first with speaker 1.5 and cutaway 6. With no face to hold viewers, a cut every second or two keeps it moving.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"timeline":{"description":"The short's draft, as Plan the cutaways lays it out, with any changes made to it. A timeline is {version: 2, title?, aspect_ratios: [9:16, 1:1, 4:5, 16:9], brand?: {back, text, accent: colours like #1c1c1c (the accent colours a caption style's key or said word; leave it out to keep captions black and white), font: the font of words on screen that name none, one of Inter Tight, Inter, Manrope, Archivo, Montserrat, Poppins, Figtree, Bricolage Grotesque, Rubik, Bebas Neue, Anton, Oswald, League Gothic, Fraunces, Playfair Display, Instrument Serif, DM Serif Display, PT Serif, Caveat, Bangers, Luckiest Guy, JetBrains Mono}, voice?: {name: one of Achernar (soft, female), Achird (friendly, male), Algenib (gravelly, male), Algieba (smooth, male), Alnilam (firm, male), Aoede (breezy, female), Autonoe (bright, female), Callirrhoe (easy-going, female), Charon (informative, male), Despina (smooth, female), Enceladus (breathy, male), Erinome (clear, female), Fenrir (excitable, male), Gacrux (mature, female), Iapetus (clear, male), Kore (firm, female), Laomedeia (upbeat, female), Leda (youthful, female), Orus (firm, male), Pulcherrima (forward, female), Puck (upbeat, male), Rasalgethi (informative, male), Sadachbia (lively, male), Sadaltager (knowledgeable, male), Schedar (even, male), Sulafat (warm, female), Umbriel (easy-going, male), Vindemiatrix (gentle, female), Zephyr (bright, female), Zubenelgenubi (casual, male)}, captions?: {style: clean (Clean: White, heavy, a few words at a time. Each word lights up as it is said.), pill (Pill: The word being said sits in a white pill, in black.), box (Box: The phrase on a dark rounded box, for busy footage.), bold (Bold: Heavy words that pop in as they are said; the word being said grows.), subtitles (Subtitles: One or two full lines, smaller, without movement: for talks and wide videos.) or off; size?: a type size, 16 to 400, pixels on a frame whose shorter side is 1080 (about 72 reads like a phone app's captions; larger means fewer words at a time); font?: one of the fonts below (Inter Tight when left out); rows?: 1 or 2 lines a caption runs to (1 when left out); width?: how wide a caption may run, as a share of the frame's shorter side, 0.2 to 3; colour?: a colour like #ffffff; said_colour?: the word being said in Pill, on its pill (near-black when left out); weight?: 100 to 900, the nearest its font has (its style's when left out); ahead?: the words not said yet, style (As its style: as its style shows them), faded (Faded: faint until each is said), full (Full: as clear as the word being said) (style when left out; none to come in a style that shows each word as it is said); outline?: false for none, or {colour?, width?: 0 to 30, percent of the type size}; shadow?: false for none, or {colour?, opacity?: 0 to 100 percent, blur?: 0 to 100 and distance?: 0 to 50, percent of the type size, the shadow dropped straight down} (the style's own when left out); in?: style (As its style: the move its style has), none (None: just there), fade (Fade: comes up from nothing), rise (Rise: lifts into place), pop (Pop: springs up with a little overshoot) (style when left out); out?: fade (Fade out: a quick fade as the next comes), none (None: just gone) (fade when left out); with a size, each caption is as many words as fit its width in its rows, never ending on a weak word; case: as_said, capitals, lower_case; place?: {x, y}: where every caption sits, its middle as shares of the frame's width and height, 0.05 to 0.95 (above the bottom of the safe area when left out); lines?: [{from, to: the first and last word of one scene's line it shows, each {scene: id, word, nth?}; text?: what it shows instead of those words, such as 58% for fifty-eight percent, at most 120 characters; place?: {x, y} for this one; hide?: true to show nothing for it; hold?: true to stay on screen until the next caption; inline?: true for text shown among the words around it, in their caption, such as a figure for words said, never a caption of its own}]: captions set by hand, none overlapping; every other caption is made from the words said, a few at a time}, pauses?: {longest?: seconds, 0 to 5, that every longer pause plays; at?: [{after: {scene: id, word, nth?}, seconds: 0 to 10}]: a pause after that word set by hand, made where there was none; or {before: {scene: id, word}, seconds} for the quiet before the first word of a line with nothing said before it, from its scene's start}: a pause is a gap of a quarter second or more between two words the voice said, or before a line's first word or after its last where nothing is said before or after it; a line not voiced yet has only the pauses set on it by hand, which play exactly as set once it is voiced; longest leaves the quiet before a first word and after a last word as voiced; shortened, lengthened or removed, the video is that much shorter or longer and everything after it moves with its words, and nothing is voiced again, transition?: cut, blur, fade, push, zoom between images (cut, none, when left out), look?: natural, mono, film, crisp over the images, progress?: true for a thin bar showing how much is left, safe?: {area: usual (TikTok, Reels and Shorts: inside the lines captions and text sit on, clear of what the apps put over a video), tiktok (TikTok: clear of TikTok's buttons, name and caption), reels (Instagram Reels: clear of Instagram's buttons, name and caption), shorts (YouTube Shorts: clear of YouTube's buttons, name and caption), even (Even margin: the same distance from every edge), none (None: only the frame's edges and middle) (usual when left out; TikTok, Reels and Shorts each in 9:16 only, the usual one in other shapes), margin?: for even, a share of the frame's shorter side, 0.01 to 0.25 (0.05 when left out)}: where nothing a person needs to read should sit, as placed gives it in each aspect ratio; keep text boxes, logos and captions inside it, music?: {prompt?: what it sounds like, its mood, instruments and pace, only when the person asks for music (made when it runs, as long as the video), src?: a file_id, from?: prompt when it was made from those words, volume 0 to 1}, scenes: [{id, line: what is said, duration: seconds, hold?: seconds it runs on after its line and its clips end, keys?: one or two words of the line, exactly as written, that carry its meaning}], images: [{id, at, until?, src?: a file_id, kind: image or video, motion: still, push, punch, zoom_in, zoom_out, pan_left, pan_right (still when left out; punch jumps closer on a key word), fit?: whole to show all of an image of another shape on a blurred copy of itself, prompt?: what it shows in a sentence or two (made from those words when it has no src), from?: prompt when it was made from them, make?: false to show the video's colours instead, box?: where it sits when not filling the frame, fades?: true for an image with an until to fade in and out (it is simply there when left out), turn?: degrees turned clockwise (-180 to 180), crop?: {left, top, right, bottom}: shares of the image trimmed from each side, 0 to 0.9, length?: a clip's own seconds (read from its file when a draft is saved), start?: seconds into a clip where it begins, to cut its beginning, to?: seconds into a clip where it stops, to cut it short, volume?: 0 to 1 and fade?: seconds for a clip's own sound}], words: [{id, value: the words shown, at most 200 characters, a new line where it breaks, at, until?, box: {x, y, w}: where the text box sits (a box as below; w is the width its words wrap at), font?: one of Inter Tight (Tight and even; every caption style's face.), Inter (The plainest, most legible sans; explainers and data.), Manrope (Calm, geometric and modern.), Archivo (Sturdy grotesque with real weight; news and how-tos.), Montserrat (The face most short-form captions are set in.), Poppins (Round geometric sans; friendly brands and lifestyle.), Figtree (Clean and warm, a little softer than Inter.), Bricolage Grotesque (Quirky editorial sans.), Rubik (Slightly rounded corners; playful but tidy.), Bebas Neue (Tall capitals; titles, numbers and sport.), Anton (Heavy, narrow capitals; the loudest hook text.), Oswald (Condensed, with weights; lists and labels.), League Gothic (Classic condensed gothic; posters and film titles.), Fraunces (Soft, old-style serif; warm stories.), Playfair Display (High-contrast serif; elegant titles.), Instrument Serif (Narrow editorial serif.), DM Serif Display (Bold display serif; quotes and headlines.), PT Serif (Classic text serif with italics; reports, history and quotes.), Caveat (Quick handwriting; notes and asides.), Bangers (Comic-book capitals; reactions and gaming.), Luckiest Guy (Fat cartoon capitals; kids, gaming and hooks.), JetBrains Mono (Monospace; code, terminals and numbers that line up.), weight?: 400 to 900 (the nearest the font has), italic?: true for its italics where it has them, size?: a type size, 16 to 400, pixels on a frame whose shorter side is 1080 (about 120 a title, 72 a line, 48 small print), colour?, align?: left, center, right, outline?: false for none, or {colour?, width?: 0 to 30, percent of the type size}; shadow?: false for none, or {colour?, opacity?: 0 to 100 percent, blur?: 0 to 100 and distance?: 0 to 50, percent of the type size, the shadow dropped straight down} (none and a soft shadow when left out; an outline may also be a colour alone), back?: a colour for a rounded box behind each line, in?: how it comes in, none (None: Just there.), fade (Fade: Comes up from nothing.), rise (Rise: Each word lifts into place.), slide (Slide: Slides in from the left.), pop (Pop: Springs up from small, with a little overshoot.), blur (Blur in: Each word sharpens out of a blur.), typewriter (Typewriter: Typed out, letter by letter.), wipe (Wipe: Revealed from left to right.), word_pop (Word by word: Words pop in one after another.), stomp (Stomp: Slams down from huge with a small shake.), highlighter (Highlighter: A marker swipes in behind the words.), letters (Letter cascade: Letters tumble in one by one.), count (Count up: Its numbers run up to their value.) (none when left out), out?: how it goes, none (None: Just gone.), fade (Fade out: Fades away.), sink (Sink: Each word drops away.), slide_out (Slide out: Slides off to the right.), pop_out (Pop out: Swells a touch, then shrinks to nothing.), blur_out (Blur out: Dissolves into a blur.), wipe_out (Wipe out: Wiped away from left to right.), backspace (Backspace: Deleted letter by letter from the end.) (none when left out)}]: text boxes, inside the safe area unless the person says where; words without a box are from before and sit at a place (top, middle, bottom) and come in by an animation (blur, rise, hook, pop, slide, fade, typewriter), sounds: [{id, src: a file_id, at, until?, volume 0 to 1, fade: seconds it fades in and out}]}. The script is said in one voice, scene after scene; a scene lasts its duration, at least as long as its line takes to say, and a scene with no line is a pause; a clip that begins in a scene, with no until or until the scene's end, plays from its start (or its first frame) to its own end (or its to) and the scene runs on until it does, then for its hold, and everything after moves along. A clip's sound plays, lowered while the voice speaks. Images, words and sounds each begin at their at and end at their until. A moment is {scene: id} (its start, or with end: true its end), {scene: id, word: one word of its line, nth?: 2 for its second time, end?: true when it has been said}, or {item: id of an image, words or sound, end?: true}, any of them with plus?: seconds after it (in tenths). An image with no until lasts until the next image with no until begins; a clip never shows past its own end (or its to); words on screen last for the scene they begin in; a sound lasts its own length. Where images show at the same time, a later one in images is drawn on top of an earlier one; where none shows, the video's colours. A logo, or anything else that stays on screen, is an image with a box from the first scene's start until the last scene's end, small (w about 0.18) in a top corner inside the safe area, unless the person says where. A box is {x, y, w}: its middle as shares of the frame's width and height (0.5, 0.5 is the middle; -1 to 2, so it can hang over an edge) and its width as a share of the frame's shorter side (0.02 to 10); its height follows its own shape, and what is outside the frame is not shown. Ids are short names, each used once. files?: [file_id, …]: files kept with the video and not yet placed in it, so its Media shows them when it is opened again. Files are file_ids from this workspace.","type":"object"},"aspect_ratio":{"description":"The aspect ratio to make it in, width to height.","type":"string","enum":["9:16","1:1","4:5","16:9"],"default":"9:16"},"part":{"type":"string","enum":["images"],"description":"Only this part, made now at its own price, to see or hear it before the rest: images (Generate an image). The settings come back with it in place and the next part is offered. Left out, all of it is made."}},"required":["timeline"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/animate_image":{"post":{"operationId":"animate_image","summary":"Animate an image","description":"Turns an image into a short video clip with sound (image to video): it starts on the image and moves as the words describe, 4, 6 or 8 seconds, wide or upright, 720p or 1080p, as an MP4. It can also end on the same image, so the clip plays on repeat with no jump.\n\nTakes image (file). Returns video (the clip, an MP4 with sound, at 24 frames a second).\n\n$0.15 to $0.80 a second of video: at 720p Recommended $0.15, Veo 3.1 Fast $0.20, Veo 3.1 $0.80; at 1080p Recommended $0.25, Veo 3.1 Fast $0.24, Veo 3.1 $0.80, up to 8 seconds.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"image":{"type":"string","description":"A file_id from create_upload, accepting image/jpeg, image/png, image/webp, up to 20 MB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result."},"prompt":{"description":"What moves and how, and what is heard, in a sentence or a few; English works best.","type":"string"},"end_on_image":{"description":"The clip ends on the image it starts on, so it plays on repeat with no jump; only at 8 seconds. Movement has to come back round for that, like waves, a fire or birds circling, not something crossing the picture one way.","type":"boolean","default":false},"model":{"description":"The model that makes it. Recommended is Scrub's pick, Veo 3.1 Lite; the others by name, each at its own price.","type":"string","enum":["recommended","Veo 3.1 Fast","Veo 3.1"],"default":"recommended"},"aspect_ratio":{"description":"Its aspect ratio, width to height. An image of another shape is cut from the middle to fill it, with no bars.","type":"string","enum":["16:9","9:16"],"default":"16:9"},"seconds":{"description":"How long it runs, in seconds.","type":"number","enum":[4,6,8],"default":8},"resolution":{"description":"Its resolution. 1080p only at 8 seconds.","type":"string","enum":["720p","1080p"],"default":"720p"}},"required":["image","prompt"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/assemble_video":{"post":{"operationId":"assemble_video","summary":"Assemble a video","description":"Draws a video from its timeline: the voice, images, words on screen, captions, logo, sounds and music, each at its moment, upright, square, portrait or wide. A reading, a picture or music already made goes in as it is, as a sound or an image, so nothing is made twice.\n\nTakes timeline (a video's timeline). Returns video, preview, captions (every caption as it is shown, from when it shows until it goes, as an SRT file. None when the video has no captions).\n\n$0.10 a minute of video, up to 3 minutes.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"timeline":{"description":"The video's timeline, as the builder shows it. A timeline is {version: 2, title?, aspect_ratios: [9:16, 1:1, 4:5, 16:9], brand?: {back, text, accent: colours like #1c1c1c (the accent colours a caption style's key or said word; leave it out to keep captions black and white), font: the font of words on screen that name none, one of Inter Tight, Inter, Manrope, Archivo, Montserrat, Poppins, Figtree, Bricolage Grotesque, Rubik, Bebas Neue, Anton, Oswald, League Gothic, Fraunces, Playfair Display, Instrument Serif, DM Serif Display, PT Serif, Caveat, Bangers, Luckiest Guy, JetBrains Mono}, voice?: {name: one of Achernar (soft, female), Achird (friendly, male), Algenib (gravelly, male), Algieba (smooth, male), Alnilam (firm, male), Aoede (breezy, female), Autonoe (bright, female), Callirrhoe (easy-going, female), Charon (informative, male), Despina (smooth, female), Enceladus (breathy, male), Erinome (clear, female), Fenrir (excitable, male), Gacrux (mature, female), Iapetus (clear, male), Kore (firm, female), Laomedeia (upbeat, female), Leda (youthful, female), Orus (firm, male), Pulcherrima (forward, female), Puck (upbeat, male), Rasalgethi (informative, male), Sadachbia (lively, male), Sadaltager (knowledgeable, male), Schedar (even, male), Sulafat (warm, female), Umbriel (easy-going, male), Vindemiatrix (gentle, female), Zephyr (bright, female), Zubenelgenubi (casual, male)}, captions?: {style: clean (Clean: White, heavy, a few words at a time. Each word lights up as it is said.), pill (Pill: The word being said sits in a white pill, in black.), box (Box: The phrase on a dark rounded box, for busy footage.), bold (Bold: Heavy words that pop in as they are said; the word being said grows.), subtitles (Subtitles: One or two full lines, smaller, without movement: for talks and wide videos.) or off; size?: a type size, 16 to 400, pixels on a frame whose shorter side is 1080 (about 72 reads like a phone app's captions; larger means fewer words at a time); font?: one of the fonts below (Inter Tight when left out); rows?: 1 or 2 lines a caption runs to (1 when left out); width?: how wide a caption may run, as a share of the frame's shorter side, 0.2 to 3; colour?: a colour like #ffffff; said_colour?: the word being said in Pill, on its pill (near-black when left out); weight?: 100 to 900, the nearest its font has (its style's when left out); ahead?: the words not said yet, style (As its style: as its style shows them), faded (Faded: faint until each is said), full (Full: as clear as the word being said) (style when left out; none to come in a style that shows each word as it is said); outline?: false for none, or {colour?, width?: 0 to 30, percent of the type size}; shadow?: false for none, or {colour?, opacity?: 0 to 100 percent, blur?: 0 to 100 and distance?: 0 to 50, percent of the type size, the shadow dropped straight down} (the style's own when left out); in?: style (As its style: the move its style has), none (None: just there), fade (Fade: comes up from nothing), rise (Rise: lifts into place), pop (Pop: springs up with a little overshoot) (style when left out); out?: fade (Fade out: a quick fade as the next comes), none (None: just gone) (fade when left out); with a size, each caption is as many words as fit its width in its rows, never ending on a weak word; case: as_said, capitals, lower_case; place?: {x, y}: where every caption sits, its middle as shares of the frame's width and height, 0.05 to 0.95 (above the bottom of the safe area when left out); lines?: [{from, to: the first and last word of one scene's line it shows, each {scene: id, word, nth?}; text?: what it shows instead of those words, such as 58% for fifty-eight percent, at most 120 characters; place?: {x, y} for this one; hide?: true to show nothing for it; hold?: true to stay on screen until the next caption; inline?: true for text shown among the words around it, in their caption, such as a figure for words said, never a caption of its own}]: captions set by hand, none overlapping; every other caption is made from the words said, a few at a time}, pauses?: {longest?: seconds, 0 to 5, that every longer pause plays; at?: [{after: {scene: id, word, nth?}, seconds: 0 to 10}]: a pause after that word set by hand, made where there was none; or {before: {scene: id, word}, seconds} for the quiet before the first word of a line with nothing said before it, from its scene's start}: a pause is a gap of a quarter second or more between two words the voice said, or before a line's first word or after its last where nothing is said before or after it; a line not voiced yet has only the pauses set on it by hand, which play exactly as set once it is voiced; longest leaves the quiet before a first word and after a last word as voiced; shortened, lengthened or removed, the video is that much shorter or longer and everything after it moves with its words, and nothing is voiced again, transition?: cut, blur, fade, push, zoom between images (cut, none, when left out), look?: natural, mono, film, crisp over the images, progress?: true for a thin bar showing how much is left, safe?: {area: usual (TikTok, Reels and Shorts: inside the lines captions and text sit on, clear of what the apps put over a video), tiktok (TikTok: clear of TikTok's buttons, name and caption), reels (Instagram Reels: clear of Instagram's buttons, name and caption), shorts (YouTube Shorts: clear of YouTube's buttons, name and caption), even (Even margin: the same distance from every edge), none (None: only the frame's edges and middle) (usual when left out; TikTok, Reels and Shorts each in 9:16 only, the usual one in other shapes), margin?: for even, a share of the frame's shorter side, 0.01 to 0.25 (0.05 when left out)}: where nothing a person needs to read should sit, as placed gives it in each aspect ratio; keep text boxes, logos and captions inside it, music?: {prompt?: what it sounds like, its mood, instruments and pace, only when the person asks for music (made when it runs, as long as the video), src?: a file_id, from?: prompt when it was made from those words, volume 0 to 1}, scenes: [{id, line: what is said, duration: seconds, hold?: seconds it runs on after its line and its clips end, keys?: one or two words of the line, exactly as written, that carry its meaning}], images: [{id, at, until?, src?: a file_id, kind: image or video, motion: still, push, punch, zoom_in, zoom_out, pan_left, pan_right (still when left out; punch jumps closer on a key word), fit?: whole to show all of an image of another shape on a blurred copy of itself, prompt?: what it shows in a sentence or two (made from those words when it has no src), from?: prompt when it was made from them, make?: false to show the video's colours instead, box?: where it sits when not filling the frame, fades?: true for an image with an until to fade in and out (it is simply there when left out), turn?: degrees turned clockwise (-180 to 180), crop?: {left, top, right, bottom}: shares of the image trimmed from each side, 0 to 0.9, length?: a clip's own seconds (read from its file when a draft is saved), start?: seconds into a clip where it begins, to cut its beginning, to?: seconds into a clip where it stops, to cut it short, volume?: 0 to 1 and fade?: seconds for a clip's own sound}], words: [{id, value: the words shown, at most 200 characters, a new line where it breaks, at, until?, box: {x, y, w}: where the text box sits (a box as below; w is the width its words wrap at), font?: one of Inter Tight (Tight and even; every caption style's face.), Inter (The plainest, most legible sans; explainers and data.), Manrope (Calm, geometric and modern.), Archivo (Sturdy grotesque with real weight; news and how-tos.), Montserrat (The face most short-form captions are set in.), Poppins (Round geometric sans; friendly brands and lifestyle.), Figtree (Clean and warm, a little softer than Inter.), Bricolage Grotesque (Quirky editorial sans.), Rubik (Slightly rounded corners; playful but tidy.), Bebas Neue (Tall capitals; titles, numbers and sport.), Anton (Heavy, narrow capitals; the loudest hook text.), Oswald (Condensed, with weights; lists and labels.), League Gothic (Classic condensed gothic; posters and film titles.), Fraunces (Soft, old-style serif; warm stories.), Playfair Display (High-contrast serif; elegant titles.), Instrument Serif (Narrow editorial serif.), DM Serif Display (Bold display serif; quotes and headlines.), PT Serif (Classic text serif with italics; reports, history and quotes.), Caveat (Quick handwriting; notes and asides.), Bangers (Comic-book capitals; reactions and gaming.), Luckiest Guy (Fat cartoon capitals; kids, gaming and hooks.), JetBrains Mono (Monospace; code, terminals and numbers that line up.), weight?: 400 to 900 (the nearest the font has), italic?: true for its italics where it has them, size?: a type size, 16 to 400, pixels on a frame whose shorter side is 1080 (about 120 a title, 72 a line, 48 small print), colour?, align?: left, center, right, outline?: false for none, or {colour?, width?: 0 to 30, percent of the type size}; shadow?: false for none, or {colour?, opacity?: 0 to 100 percent, blur?: 0 to 100 and distance?: 0 to 50, percent of the type size, the shadow dropped straight down} (none and a soft shadow when left out; an outline may also be a colour alone), back?: a colour for a rounded box behind each line, in?: how it comes in, none (None: Just there.), fade (Fade: Comes up from nothing.), rise (Rise: Each word lifts into place.), slide (Slide: Slides in from the left.), pop (Pop: Springs up from small, with a little overshoot.), blur (Blur in: Each word sharpens out of a blur.), typewriter (Typewriter: Typed out, letter by letter.), wipe (Wipe: Revealed from left to right.), word_pop (Word by word: Words pop in one after another.), stomp (Stomp: Slams down from huge with a small shake.), highlighter (Highlighter: A marker swipes in behind the words.), letters (Letter cascade: Letters tumble in one by one.), count (Count up: Its numbers run up to their value.) (none when left out), out?: how it goes, none (None: Just gone.), fade (Fade out: Fades away.), sink (Sink: Each word drops away.), slide_out (Slide out: Slides off to the right.), pop_out (Pop out: Swells a touch, then shrinks to nothing.), blur_out (Blur out: Dissolves into a blur.), wipe_out (Wipe out: Wiped away from left to right.), backspace (Backspace: Deleted letter by letter from the end.) (none when left out)}]: text boxes, inside the safe area unless the person says where; words without a box are from before and sit at a place (top, middle, bottom) and come in by an animation (blur, rise, hook, pop, slide, fade, typewriter), sounds: [{id, src: a file_id, at, until?, volume 0 to 1, fade: seconds it fades in and out}]}. The script is said in one voice, scene after scene; a scene lasts its duration, at least as long as its line takes to say, and a scene with no line is a pause; a clip that begins in a scene, with no until or until the scene's end, plays from its start (or its first frame) to its own end (or its to) and the scene runs on until it does, then for its hold, and everything after moves along. A clip's sound plays, lowered while the voice speaks. Images, words and sounds each begin at their at and end at their until. A moment is {scene: id} (its start, or with end: true its end), {scene: id, word: one word of its line, nth?: 2 for its second time, end?: true when it has been said}, or {item: id of an image, words or sound, end?: true}, any of them with plus?: seconds after it (in tenths). An image with no until lasts until the next image with no until begins; a clip never shows past its own end (or its to); words on screen last for the scene they begin in; a sound lasts its own length. Where images show at the same time, a later one in images is drawn on top of an earlier one; where none shows, the video's colours. A logo, or anything else that stays on screen, is an image with a box from the first scene's start until the last scene's end, small (w about 0.18) in a top corner inside the safe area, unless the person says where. A box is {x, y, w}: its middle as shares of the frame's width and height (0.5, 0.5 is the middle; -1 to 2, so it can hang over an edge) and its width as a share of the frame's shorter side (0.02 to 10); its height follows its own shape, and what is outside the frame is not shown. Ids are short names, each used once. files?: [file_id, …]: files kept with the video and not yet placed in it, so its Media shows them when it is opened again. Files are file_ids from this workspace.","type":"object"},"aspect_ratio":{"description":"The aspect ratio it is drawn in, width to height. 9:16 is upright for stories and reels, 1:1 square, 4:5 portrait for feeds, 16:9 wide.","type":"string","enum":["9:16","1:1","4:5","16:9"],"default":"9:16"}},"required":["timeline"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/burn_captions":{"post":{"operationId":"burn_captions","summary":"Burn captions into a video","description":"Draws captions onto a video's picture (burned-in subtitles), from a subtitle file, captions written out or one line of text, in the place, style and size chosen.\n\nTakes src (file), subtitle_file (file). Give exactly one of: text, start and end; or captions; or subtitle_file. Returns video, preview, edl (the captions as drawn, each with its words, times, place and style, and the source they were drawn on).\n\n$0.10 a minute of video, up to 60 minutes.\n\nAfterwards, change start, end, position, text or captions with adjust; quote_adjustment prices the change.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"src":{"type":"string","description":"A file_id from create_upload, accepting video/*, up to 2 GB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result."},"subtitle_file":{"type":"string","description":"A file_id from create_upload, accepting application/vnd.scrub.timed-text+json, application/json, application/x-subrip, text/vtt, text/plain, up to 16 MB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result. Without one, transcribe (Transcribe a video) from the file given as src makes the transcript_file that convert (Convert a transcript) with as json makes one from: run them in that order first and pass the last one's job_id here."},"text":{"description":"One caption's text, with start and end.","type":"string"},"start":{"description":"When that one caption appears, in seconds.","type":"number","minimum":0},"end":{"description":"Greater than start.","type":"number"},"captions":{"description":"Captions written out, each with start and end in seconds and its text.","type":"array","maxItems":5000,"items":{"type":"object","properties":{"start":{"type":"number","minimum":0,"description":"Seconds"},"end":{"type":"number","description":"Seconds, after start"},"text":{"type":"string","maxLength":500}},"required":["start","end","text"]}},"position":{"type":"string","enum":["lower_third","centre","top_left"],"default":"lower_third"},"style":{"description":"How the captions look. clean: White, heavy, a few words at a time. Each word lights up as it is said. pill: The word being said sits in a white pill, in black. box: The phrase on a dark rounded box, for busy footage. bold: Heavy words that pop in as they are said; the word being said grows. subtitles: One or two full lines, smaller, without movement: for talks and wide videos.","type":"string","enum":["clean","pill","box","bold","subtitles"],"default":"clean"},"font":{"description":"The font the captions are set in. Inter Tight: Tight and even; every caption style's face. Inter: The plainest, most legible sans; explainers and data. Manrope: Calm, geometric and modern. Archivo: Sturdy grotesque with real weight; news and how-tos. Montserrat: The face most short-form captions are set in. Poppins: Round geometric sans; friendly brands and lifestyle. Figtree: Clean and warm, a little softer than Inter. Bricolage Grotesque: Quirky editorial sans. Rubik: Slightly rounded corners; playful but tidy. Bebas Neue: Tall capitals; titles, numbers and sport. Anton: Heavy, narrow capitals; the loudest hook text. Oswald: Condensed, with weights; lists and labels. League Gothic: Classic condensed gothic; posters and film titles. Fraunces: Soft, old-style serif; warm stories. Playfair Display: High-contrast serif; elegant titles. Instrument Serif: Narrow editorial serif. DM Serif Display: Bold display serif; quotes and headlines. PT Serif: Classic text serif with italics; reports, history and quotes. Caveat: Quick handwriting; notes and asides. Bangers: Comic-book capitals; reactions and gaming. Luckiest Guy: Fat cartoon capitals; kids, gaming and hooks. JetBrains Mono: Monospace; code, terminals and numbers that line up.","type":"string","enum":["Inter Tight","Inter","Manrope","Archivo","Montserrat","Poppins","Figtree","Bricolage Grotesque","Rubik","Bebas Neue","Anton","Oswald","League Gothic","Fraunces","Playfair Display","Instrument Serif","DM Serif Display","PT Serif","Caveat","Bangers","Luckiest Guy","JetBrains Mono"],"default":"Inter Tight"},"size":{"description":"The captions' type size, in pixels on a frame whose shorter side is 1080; larger shows fewer words at a time.","type":"number","minimum":16,"maximum":400,"default":72},"rows":{"description":"How many lines a caption runs to; as many words show at once as fit.","type":"number","minimum":1,"maximum":2,"default":1},"case":{"description":"Capital letters as said, all capitals, or all lower case.","type":"string","enum":["as_said","capitals","lower_case"],"default":"as_said"},"weight":{"description":"How heavy its letters are; the nearest weight its font has is drawn. style: its style's own","type":"string","enum":["style","100","200","300","400","500","600","700","800","900"],"default":"style"},"ahead":{"description":"How the words of a caption not said yet look, in a style that shows a caption's words together. style: as its style shows them faded: faint until each is said full: as clear as the word being said","type":"string","enum":["style","faded","full"],"default":"style"},"in":{"description":"How each caption comes in. style: the move its style has none: just there fade: comes up from nothing rise: lifts into place pop: springs up with a little overshoot","type":"string","enum":["style","none","fade","rise","pop"],"default":"style"},"out":{"description":"How each caption goes as the next comes. fade: a quick fade as the next comes none: just gone","type":"string","enum":["fade","none"],"default":"fade"}},"required":["src"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/compress_video":{"post":{"operationId":"compress_video","summary":"Compress a video","description":"Makes a video file smaller to send or upload: looking the same, much smaller with no difference most people notice, or as small as it goes.\n\nTakes src (file). Returns video.\n\n$0.02 a minute of video, up to 30 minutes.\n\nAfterwards, change quality with adjust; quote_adjustment prices the change.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"src":{"type":"string","description":"A file_id from create_upload, accepting video/*, up to 2 GB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result. Or a file_id (cf_…) from list_computers: a file on the person’s computer, run there by the Scrub app while it is open, at the price there."},"quality":{"description":"How much to keep. Looks the same (looks_the_same) is hard to tell from the original; Balanced (balanced) is much smaller, with no difference most people notice; Smallest (smallest) is smallest, a little softer. Leave it out unless the person said which: they are asked, each choice priced with what it comes to.","type":"string","enum":["looks_the_same","balanced","smallest"],"default":"balanced"}},"required":["src"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/convert":{"post":{"operationId":"convert","summary":"Convert a transcript","description":"Writes a transcript as subtitles (SRT or VTT), text, Markdown, HTML or JSON, grouped by caption, sentence, paragraph or word, from a transcription or a transcript or subtitle file; the whole of it, or a stretch timed from its start.\n\nTakes transcript_file (file). Returns file.\n\nFree.\n\nAfterwards, change as or by with adjust; quote_adjustment prices the change.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"transcript_file":{"type":"string","description":"A file_id from create_upload, accepting application/vnd.scrub.transcript+json, application/json, application/x-subrip, text/vtt, text/plain, up to 16 MB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result. Without one, transcribe (Transcribe a video) makes one, or transcribe_audio (Transcribe audio) makes one: run it first and pass its job_id here."},"as":{"description":"How it is written. srt and vtt are subtitle files; markdown and html carry a timestamp on each part.","type":"string","enum":["text","markdown","html","json","srt","vtt"],"default":"srt"},"by":{"description":"How words are grouped. auto is caption for srt and vtt, paragraph for text, markdown and html, and word for json. Captions are at most two lines of 42 characters and seven seconds.","type":"string","enum":["auto","caption","sentence","paragraph","word"],"default":"auto"},"start":{"description":"Seconds into the transcript where the stretch begins; its words are timed from here.","type":"number","minimum":0,"default":0},"end":{"description":"Seconds into the transcript where the stretch ends; at 0 it runs to the end.","type":"number","minimum":0,"default":0}},"required":["transcript_file"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/extract_audio":{"post":{"operationId":"extract_audio","summary":"Extract audio from a video","description":"Extracts the audio from a video as an audio file (M4A), the whole length, copied untouched when it can be. Useful on its own, and much smaller to send than the video when only the sound is needed, such as to transcribe it. A video with no sound is refused.\n\nTakes src (file). Returns audio.\n\n$0.01 an hour of video, up to 6 hours.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"src":{"type":"string","description":"A file_id from create_upload, accepting video/*, up to 4 GB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result. Or a file_id (cf_…) from list_computers: a file on the person’s computer, run there by the Scrub app while it is open, at the price there."}},"required":["src"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/find_moments":{"post":{"operationId":"find_moments","summary":"Find the moments","description":"Finds the moments in a recording that stand alone as clips, from its transcription: up to so many or exactly so many, each a run of whole sentences between a shortest and a longest length, with a title, when it is said, its opening words and why it stands alone, as a table.\n\nTakes transcript (file). Returns moments (the moments, one row each in the order they are said, with its title, when it starts and ends, how many seconds it runs, its opening line and why it stands alone).\n\n$0.10 an hour of recording, up to 10 hours.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"transcript":{"type":"string","description":"A file_id from create_upload, accepting application/vnd.scrub.transcript+json, application/json, up to 16 MB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result. Without one, transcribe (Transcribe a video) makes one, or transcribe_audio (Transcribe audio) makes one: run it first and pass its job_id here."},"moments":{"description":"The most moments it finds; fewer when fewer stand alone.","type":"number","minimum":1,"maximum":10,"default":5},"exactly":{"description":"Finds exactly that many moments, where the recording holds them.","type":"boolean","default":false},"shortest":{"description":"The shortest a moment runs, in seconds.","type":"number","minimum":5,"maximum":170,"default":20},"longest":{"description":"Greater than shortest.","type":"number","minimum":10,"maximum":180,"default":60}},"required":["transcript"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/generate_image":{"post":{"operationId":"generate_image","summary":"Generate an image","description":"Creates an image from a description (text to image), upright, square, portrait or wide, as a JPEG. Reference images, optional, keep a person, a product, a place or a look from images you give (image to image).\n\nTakes prompt (text), references (a list of files, up to 3, optional). Returns image (the image, a JPEG).\n\n$0.07 to $0.27 an image: Recommended $0.07, Nano Banana 2 $0.14, Nano Banana Pro $0.27, GPT Image 2 $0.11. Recommended picks by what the words ask: for words in the picture Nano Banana Pro; for a drawn style Recommended; for many people moving GPT Image 2; for people and faces GPT Image 2; for a product shot Recommended; for a landscape Recommended.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"references":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":3,"description":"A list: A file_id from create_upload, accepting image/jpeg, image/png, image/webp, up to 20 MB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result. All of them are one job."},"prompt":{"description":"What the image shows and how it looks, in a sentence or a few; any language. It has no words in it unless you ask for them.","type":"string"},"model":{"description":"The model that draws it. Recommended is Scrub's pick for what the words ask, the best scored for the price; the others by name, each at its own price. Recommended may run Nano Banana Pro at $0.27 an image or GPT Image 2 at $0.11 an image, by what the words ask. The words choose the model, and so the price: quote with the exact words you will run.","type":"string","enum":["recommended","Nano Banana 2","Nano Banana Pro","GPT Image 2"],"default":"recommended"},"aspect_ratio":{"description":"Its aspect ratio, width to height.","type":"string","enum":["9:16","1:1","4:5","16:9"],"default":"1:1"},"goes_with":{"description":"For a video, what goes with the line the prompt says, such as what the video is about. Scrub picks what to show, never words. Empty, it draws the prompt.","type":"string","default":""}},"required":["prompt"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/generate_music":{"post":{"operationId":"generate_music","summary":"Generate music","description":"Composes music from a description of its mood, instruments and pace, up to three minutes, as an MP3: instrumental unless singing is asked for, or a song sung with given lyrics.\n\nTakes prompt (text), lyrics (text). Returns music (the music, an MP3).\n\n$0.08 per 30 seconds of music, at least $0.10, at most $0.30, up to 180 seconds.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prompt":{"description":"The music in a sentence or a few, such as its mood, instruments, pace and who sings; any language. Instrumental unless you ask for singing or give lyrics.","type":"string"},"lyrics":{"description":"Words to sing, in any language, its parts marked like [Verse] and [Chorus] if you like; sung as written. Without them it is instrumental, unless the prompt asks for singing, when lyrics are written for it.","type":"string","default":""},"seconds":{"description":"How long it runs, in seconds, up to three minutes; it ends in a fade.","type":"number","minimum":10,"maximum":180,"default":30}},"required":["prompt"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/generate_video":{"post":{"operationId":"generate_video","summary":"Generate a video","description":"Creates a short video clip with sound from a description (text to video), 4, 6 or 8 seconds, wide or upright, 720p or 1080p, as an MP4. Reference images, optional, keep a person, a product, a place or a look from images you give in the clip.\n\nTakes prompt (text), references (a list of files, up to 3, optional, with model Veo 3.1 Fast or Veo 3.1, with seconds 8). Returns video (the clip, an MP4 with sound, at 24 frames a second).\n\n$0.15 to $0.80 a second of video: at 720p Recommended $0.15, Veo 3.1 Fast $0.20, Veo 3.1 $0.80; at 1080p Recommended $0.25, Veo 3.1 Fast $0.24, Veo 3.1 $0.80, up to 8 seconds. Recommended picks by what the words ask: for speech and sound Recommended; for words in the picture Veo 3.1 Fast; for a drawn style Recommended; for many people moving Recommended (no model does it well yet); for people and faces Recommended; for a product shot Recommended (no model does it well yet); for a landscape Recommended.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"references":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":3,"description":"A list: A file_id from create_upload, accepting image/jpeg, image/png, image/webp, up to 20 MB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result. All of them are one job."},"prompt":{"description":"What happens, how it looks and what is heard, in a sentence or a few; English works best. Describe how a place or thing looks rather than naming it, since a named landmark is drawn as the model imagines it.","type":"string"},"model":{"description":"The model that makes it. Recommended is Scrub's pick for what the words ask, the best scored for the price; the others by name, each at its own price. Recommended may run Veo 3.1 Fast at $0.20 a second, by what the words ask. The words choose the model, and so the price: quote with the exact words you will run.","type":"string","enum":["recommended","Veo 3.1 Fast","Veo 3.1"],"default":"recommended"},"aspect_ratio":{"description":"Its aspect ratio, width to height.","type":"string","enum":["16:9","9:16"],"default":"16:9"},"seconds":{"description":"How long it runs, in seconds.","type":"number","enum":[4,6,8],"default":8},"resolution":{"description":"Its resolution. 1080p only at 8 seconds.","type":"string","enum":["720p","1080p"],"default":"720p"}},"required":["prompt"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/make_loop":{"post":{"operationId":"make_loop","summary":"Make it loop","description":"Makes a loop of a video from its own frames that plays on repeat with no jump, for a background or a post. It finds where the picture and its motion come back to the start and keeps the frames between, without sound. A video whose movement never comes back, like something crossing the picture one way, is refused.\n\nTakes src (file). Returns video.\n\n$0.01 a second of video, up to 60 seconds.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"src":{"type":"string","description":"A file_id from create_upload, accepting video/*, up to 512 MB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result. Without one, animate_image (Animate an image) makes one, or generate_video (Generate a video) makes one: run it first and pass its job_id here."}},"required":["src"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/make_spreadsheet":{"post":{"operationId":"make_spreadsheet","summary":"Make a spreadsheet","description":"Writes a table as an Excel file and a CSV, from a table another action read, a CSV or JSON file, or rows typed or pasted.\n\nTakes table_file (file). Give exactly one of: table_file; or table_text. Returns excel, csv, table (the table as written into the files).\n\nFree.\n\nAfterwards, change columns or sheet with adjust; quote_adjustment prices the change.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"table_file":{"type":"string","description":"A file_id from create_upload, accepting application/vnd.scrub.table+json, text/csv, text/tab-separated-values, application/json, text/plain, up to 20 MB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result. Without one, read_fields (Read documents into a table) makes one: run it first and pass its job_id here."},"table_text":{"description":"A table typed or pasted, one row a line, values separated by commas or tabs, the first line the column names.","type":"string"},"columns":{"description":"Which columns to include, in order, by name, comma separated. Leave it empty for every column.","type":"string","default":""},"sheet":{"description":"The name of the sheet in the Excel file.","type":"string","default":"Sheet 1"}},"required":[]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/plan_cutaways":{"post":{"operationId":"plan_cutaways","summary":"Plan the cutaways","description":"Lays a stretch of a recording out as a short to finish, from its transcription: the stretch found by its times or words, the speaker upright and centred (from audio alone, pictures throughout), cutaways on its key points saying what each shows, callouts on figures said, a hook. Changes no word said and makes no image.\n\nTakes src (file), transcript (file). Returns timeline (the short as a timeline to change before it is made, upright, its lines said in the recording, the recording under everything (from audio alone, the cutaways one after another instead), each cutaway on its words saying what it shows, each callout a text box on its words, and its hook, its title or nothing on top, as asked).\n\n$0.07 a plan.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"src":{"type":"string","description":"A file_id from create_upload, accepting video/*, audio/*, up to 4 GB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result."},"transcript":{"type":"string","description":"A file_id from create_upload, accepting application/vnd.scrub.transcript+json, application/json, up to 16 MB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result. Without one, transcribe (Transcribe a video) from the file given as src when it is a video makes one, or transcribe_audio (Transcribe audio) from the file given as src when it is an audio file makes one: run it first and pass its job_id here."},"moment":{"description":"Which stretch, by its start and end (8:48 to 9:35) or by what is said in it, and what it is about; a title it gives names the short. Or one row of a table: find_moments (Find the moments) from the file given as transcript makes the table; run it, then give one row's words here, every column by its label.","type":"string"},"top":{"description":"What sits at the top of the short. Hook at the start is a line that makes someone stop scrolling, for its first 3 seconds; Title throughout names it the whole way through; None leaves the top clear.","type":"string","enum":["hook_at_the_start","title_throughout","none"],"default":"hook_at_the_start"},"quiet":{"description":"Any quiet longer than this, in seconds, is cut down to half a second (or to this, when shorter), from the sound and the picture together.","type":"number","minimum":0.3,"maximum":10,"default":1},"speaker":{"description":"The longest the speaker is on screen before a cutaway, in seconds. From audio alone nobody is on screen, and every stretch is a cutaway.","type":"number","minimum":1,"maximum":30,"default":4},"cutaway":{"description":"The longest a cutaway shows, in seconds; from audio alone, the longest each picture shows.","type":"number","minimum":1,"maximum":10,"default":3},"callouts":{"description":"The most callouts, each a figure or a short phrase said (at most five words), shown big on the words that say it; 0 for none.","type":"number","minimum":0,"maximum":4,"default":4}},"required":["moment"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/read_fields":{"post":{"operationId":"read_fields","summary":"Read documents into a table","description":"Reads photos, scans or PDFs into a table (data extraction), one row per item found, with the columns asked for or chosen from what is printed.\n\nTakes documents (a list of files, up to 200). Returns rows (the table read, one row per item found, with the file and page each came from).\n\n$0.05 a page, up to 200 pages.\n\nAfterwards, change fields or row with adjust; quote_adjustment prices the change.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"documents":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":200,"description":"A list: A file_id from create_upload, accepting image/jpeg, image/png, image/webp, image/heic, image/heif, application/pdf, up to 14 MB a photo, 30 MB a PDF. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result. All of them are one job."},"fields":{"description":"What to read, each a column of the table. A field has a name, what it means when the name is not enough, and the kind of value it is (text, number, amount, currency, date, or one of a list of choices). Left empty, the columns are chosen from what is printed on the documents.","type":"array","minItems":0,"maxItems":30,"items":{"type":"object","properties":{"name":{"type":"string","maxLength":60,"description":"The column name"},"type":{"type":"string","enum":["text","number","amount","currency","date","choice"],"description":"amount is money; currency is its ISO 4217 code; a date is written YYYY-MM-DD. Text when not given."},"description":{"type":"string","maxLength":400,"description":"What it means, when the name is not enough"},"choices":{"type":"array","items":{"type":"string"},"description":"For a choice: the values it may take"}},"required":["name"]},"default":[]},"row":{"description":"Left as document, every document is read, and each row says what kind it is. Name a kind, such as invoice, or several joined by or, and anything else is left out and not charged. Several on one page, or one running over several pages, are each one row.","type":"string","default":"document"}},"required":["documents"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/read_text":{"post":{"operationId":"read_text","summary":"Read documents as text","description":"Reads the text of photos, scans and PDFs (OCR), every page, each headed by its file and page.\n\nTakes documents (a list of files, up to 200). Returns text (the text of every page, each headed by its file and page), pages.\n\n$0.01 a page, up to 200 pages.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"documents":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":200,"description":"A list: A file_id from create_upload, accepting image/jpeg, image/png, image/webp, image/heic, image/heif, application/pdf, up to 20 MB a photo, 30 MB a PDF. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result. All of them are one job."}},"required":["documents"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/text_to_speech":{"post":{"operationId":"text_to_speech","summary":"Text to speech","description":"Generates speech from text (text to speech, TTS): the words read aloud as one audio file, such as a voiceover or narration, in a chosen voice, male or female, from soft to firm, as one take.\n\nTakes text (text). Returns speech (the text spoken, as one file).\n\n$0.01 per 12 seconds of speech, up to 240 seconds.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"description":"What is said, exactly as written, as one take; any language.","type":"string"},"voice":{"description":"Who says it. No voice takes an accent, Scottish or other. Achernar: soft, female Achird: friendly, male Algenib: gravelly, male Algieba: smooth, male Alnilam: firm, male Aoede: breezy, female Autonoe: bright, female Callirrhoe: easy-going, female Charon: informative, male Despina: smooth, female Enceladus: breathy, male Erinome: clear, female Fenrir: excitable, male Gacrux: mature, female Iapetus: clear, male Kore: firm, female Laomedeia: upbeat, female Leda: youthful, female Orus: firm, male Pulcherrima: forward, female Puck: upbeat, male Rasalgethi: informative, male Sadachbia: lively, male Sadaltager: knowledgeable, male Schedar: even, male Sulafat: warm, female Umbriel: easy-going, male Vindemiatrix: gentle, female Zephyr: bright, female Zubenelgenubi: casual, male","type":"string","enum":["Achernar","Achird","Algenib","Algieba","Alnilam","Aoede","Autonoe","Callirrhoe","Charon","Despina","Enceladus","Erinome","Fenrir","Gacrux","Iapetus","Kore","Laomedeia","Leda","Orus","Pulcherrima","Puck","Rasalgethi","Sadachbia","Sadaltager","Schedar","Sulafat","Umbriel","Vindemiatrix","Zephyr","Zubenelgenubi"],"default":"Kore"}},"required":["text"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/transcribe":{"post":{"operationId":"transcribe","summary":"Transcribe a video","description":"Transcribes a video: writes down what is said in it, every word with its time (speech to text), in the language it detects or the one given.\n\nTakes src (file). Returns transcript.\n\n$0.15 per 10 minutes of audio, up to 360 minutes.\n\nAfterwards, change language with adjust; quote_adjustment prices the change.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"src":{"type":"string","description":"A file_id from create_upload, accepting video/*, up to 4 GB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result."},"language":{"description":"Left as auto, the language is detected. To choose one, give its code, such as en, fr or de.","type":"string","default":"auto"}},"required":["src"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/transcribe_audio":{"post":{"operationId":"transcribe_audio","summary":"Transcribe audio","description":"Transcribes audio, such as a call, a podcast or a voice note: writes down what is said, every word with its time (speech to text), in the language it detects or the one given.\n\nTakes src (file). Returns transcript.\n\n$0.15 per 10 minutes of audio, up to 360 minutes.\n\nAfterwards, change language with adjust; quote_adjustment prices the change.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"src":{"type":"string","description":"A file_id from create_upload, accepting audio/*, up to 4 GB. Get one with create_upload. Or the job_id of a finished job that made a file of this kind: that file is used. Pass the job_id rather than retyping its result."},"language":{"description":"Left as auto, the language is detected. To choose one, give its code, such as en, fr or de.","type":"string","default":"auto"}},"required":["src"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/voice_script":{"post":{"operationId":"voice_script","summary":"Voice a script","description":"Voices a script line by line in a chosen voice, as one take with every word's time: each line's stretch of the audio, a changed line voiced again on its own, lines timed to subtitles or a video.\n\nTakes script (text). Returns voice (the voice as one file, each line where it plays), script (the script with each line's stretch of the take, where it plays in the voice file and how long, and every word's time; given again with a line changed, only that line is voiced), timeline (given a video's timeline, the same timeline with each scene's stretch of the take, its length and its word timings set. None when given a script).\n\n$0.01 per 12 seconds of speech, up to 240 seconds.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"script":{"description":"What is said, line by line, as one take in its voice: text, each paragraph a line (each line when no blank lines part them); a subtitle file's text, SRT or VTT, each cue a line that starts at its time; {lines: [{id, text, at?, until?}], voice?: {name}, timing?: cues or straight}, at and until in seconds; or a video's timeline, whose scenes are its lines. A line voiced before, as it reads and in the same voice, is reused; words moved between lines of one take are cut from it again, not voiced. A script is text, or {lines: [{id, text, at?, until?}], voice?: {name: one of Achernar (soft, female), Achird (friendly, male), Algenib (gravelly, male), Algieba (smooth, male), Alnilam (firm, male), Aoede (breezy, female), Autonoe (bright, female), Callirrhoe (easy-going, female), Charon (informative, male), Despina (smooth, female), Enceladus (breathy, male), Erinome (clear, female), Fenrir (excitable, male), Gacrux (mature, female), Iapetus (clear, male), Kore (firm, female), Laomedeia (upbeat, female), Leda (youthful, female), Orus (firm, male), Pulcherrima (forward, female), Puck (upbeat, male), Rasalgethi (informative, male), Sadachbia (lively, male), Sadaltager (knowledgeable, male), Schedar (even, male), Sulafat (warm, female), Umbriel (easy-going, male), Vindemiatrix (gentle, female), Zephyr (bright, female), Zubenelgenubi (casual, male)}, timing?: cues (each line starts at its at, the default) or straight (one after another)}; {text, voice?, timing?} reads text as given. A subtitle file's text (SRT or VTT) is read as one line for each cue, at its times. Ids are short names, each used once; a line given back voiced keeps its recording, so send it back as it came to voice only what changed.","anyOf":[{"type":"string"},{"type":"object"}]},"lines":{"description":"Some of the script's lines, by id, comma-separated, to voice only those, each on its own; every other line keeps the voice it has, a changed one still waiting to be voiced. Empty, every line that needs it is voiced.","type":"string","default":""}},"required":["script"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/write_script":{"post":{"operationId":"write_script","summary":"Draft a video script","description":"Drafts a short video from an idea, or divides a script given into scenes: what is said, the words on screen, the images and the music, to change before it is voiced and made.\n\nTakes idea (text). Returns timeline (the draft as a timeline, scene by scene, each with what is said and the words on screen, and its images, each from a moment of the line with what it shows, and the music it asks for, in words, to change before it is voiced and made).\n\n$0.05 a draft.","tags":["Work"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"idea":{"description":"What the video is about, in a sentence or a few; or a script, whose words are kept as they are, divided into scenes, in its own language. Music it asks for is described in the draft.","type":"string"},"seconds":{"description":"About how long the video runs, in seconds.","type":"number","minimum":10,"maximum":120,"default":30}},"required":["idea"],"description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line."}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/quote":{"post":{"operationId":"quote","summary":"Price work before it runs","description":"Prices one call or a whole chain of calls before anything runs, with the workspace spending cap. Writes nothing and charges nothing. Where Scrub can tell, it also says about how big a file would come out.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"steps":{"type":"array","minItems":1,"maxItems":10,"description":"The calls, in the order they would run.","items":{"type":"object","properties":{"tool":{"type":"string"},"arguments":{"type":"object"}},"required":["tool","arguments"]}}},"required":["steps"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/run_flow":{"post":{"operationId":"run_flow","summary":"Run a flow","description":"Runs a flow by its name (flow_…) as calling that name does: one job at one price. For a flow saved in this conversation, which the tools listed before do not show. quote gives its price first, with the flow's name and its inputs.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Charged to the person’s Scrub credit. Before the first run with a price in a conversation, quote it with the exact arguments, never from the rates, then tell them it is Scrub’s, with that price, and wait for their yes; after that, run what they ask without asking again. After the result, say what Scrub charged and the credit left in one short line.","properties":{"flow":{"type":"string","description":"Its name, flow_…"},"arguments":{"type":"object","description":"Its inputs and settings, as open_flow gives them"}},"required":["flow","arguments"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/job_status":{"post":{"operationId":"job_status","summary":"Check a job","description":"Where a job got to, and its result when it has one. Work that takes longer than a request can hold is handed back as a job id: ask this for it. While it runs: the stage, its count, and fraction_done, how much of the whole job is finished, with fraction_by: time when its steps are weighed by how long they usually take, steps when only counted; and seconds_left, about how long is left, where that can be told. For a tool’s run it also gives each step’s price and state, the files a finished step made, and the jobs made for the run before it started, with what they came to in all. Free.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"job_id":{"type":"string"}},"required":["job_id"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/stop_job":{"post":{"operationId":"stop_job","summary":"Stop a job","description":"Stops a job that is still running, when the person asks to: it ends stopped and is not charged, and a tool’s finished steps are kept, so running it again reuses them. A job that has finished, or one answered at once, is left as it is. Free.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"job_id":{"type":"string"}},"required":["job_id"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/next_part":{"post":{"operationId":"next_part","summary":"Ask the next part","description":"What a tool's work offers next on these settings, free: the question of the part it is at and each choice with its price and the settings it runs with, as a result carries it in ask. For work done another way, such as on the tool's page. Only for tools made one part at a time.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tool":{"type":"string","description":"The tool"},"params":{"type":"object","additionalProperties":true,"description":"Its settings now"}},"required":["tool","params"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/quote_adjustment":{"post":{"operationId":"quote_adjustment","summary":"Price a change","description":"Prices a change to a finished job without running it. Free. Returns what adjust would charge for the same patch, and which params it changes. Adjustable params by action: burn_captions: start, end, position, text, captions; compress_video: quality; convert: as, by; make_spreadsheet: columns, sheet; read_fields: fields, row; transcribe: language; transcribe_audio: language.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"job_id":{"type":"string"},"patch":{"type":"array","description":"An RFC 6902 JSON Patch against the job's params, e.g. [{\"op\":\"replace\",\"path\":\"/start\",\"value\":15.3}]. replace, add and test are accepted.","items":{"type":"object","properties":{"op":{"type":"string","enum":["replace","add","test"]},"path":{"type":"string"},"value":{}},"required":["op","path","value"]}}},"required":["job_id","patch"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/adjust":{"post":{"operationId":"adjust","summary":"Change a finished job","description":"Re-runs a finished job with a patch applied, as a new job linked to the original, which is kept as it was. Charged the price quote_adjustment returns for the same patch. A chain of adjustments stops at 10. Adjustable params by action: burn_captions: start, end, position, text, captions; compress_video: quality; convert: as, by; make_spreadsheet: columns, sheet; read_fields: fields, row; transcribe: language; transcribe_audio: language.","tags":["Prices and jobs"],"x-scrub-priced":true,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"job_id":{"type":"string"},"patch":{"type":"array","description":"An RFC 6902 JSON Patch against the job's params, e.g. [{\"op\":\"replace\",\"path\":\"/start\",\"value\":15.3}]. replace, add and test are accepted.","items":{"type":"object","properties":{"op":{"type":"string","enum":["replace","add","test"]},"path":{"type":"string"},"value":{}},"required":["op","path","value"]}},"nonce":{"type":"string","description":"Optional. Send the same nonce again to get the same job back rather than a second charge."}},"required":["job_id","patch"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/create_upload":{"post":{"operationId":"create_upload","summary":"Upload a file","description":"Gets a place for one file and returns its file_id. upload_page is a link where a person picks the file: give it to them, and when they say it is uploaded, check with upload_status. An AI that can send bytes passes bytes and content_type to get upload_url as well. Files up to 4096 MB, larger than chat attachments. An upload no tool uses goes after a day; with keep it stays in the person's Files for 90 days, as any file does. Links last an hour. Free.","tags":["Files"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"filename":{"type":"string","description":"The name of the file, e.g. interview.mp4, if you know it"},"content_type":{"type":"string","description":"Its media type, e.g. video/mp4. Only needed with bytes."},"bytes":{"type":"number","description":"Its size in bytes. Only if you will send the bytes yourself."},"keep":{"type":"boolean","description":"Keep it in Files for 90 days even if no tool uses it, for a person putting a file in Files. Off by default."}},"required":[]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/upload_status":{"post":{"operationId":"upload_status","summary":"Check an upload","description":"Checks whether a file has arrived at a file_id from create_upload, and for a photo, scan or PDF how many pages it has. Free. Use it after the person says the upload finished, before passing the file_id to a tool.","tags":["Files"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"file_id":{"type":"string"}},"required":["file_id"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/list_files":{"post":{"operationId":"list_files","summary":"List your files","description":"Lists the files in this workspace, newest first, fifty at a time: uploads and results, each with its file_id to pass as a file input, its size, and what made it (with its job_id, and the results of that job that fill a setting, by type: a voice’s script). Free. Give tool (and input) to list only the files that input takes, kind to list only images, clips, sound or documents, name to find files whose name has those words, and file_ids to include those files however old. total says how many match; when more is true, pass the last file_id as before for the next fifty.","tags":["Files"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tool":{"type":"string","description":"An action or tool id, to list only files it takes"},"input":{"type":"string","description":"One of its file inputs, by name"},"kind":{"type":"array","items":{"type":"string","enum":["image","video","audio","document"]},"description":"Only these kinds of file: image, video, audio, or document (anything else: PDFs, spreadsheets, text, subtitles, transcripts)"},"file_ids":{"type":"array","items":{"type":"string"},"description":"Files to include however old, by file_id"},"name":{"type":"string","description":"Only files whose name has these words, however old"},"before":{"type":"string","description":"The next page: the files after this file_id, the last one listed"}}}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/download_file":{"post":{"operationId":"download_file","summary":"Download a file","description":"A link to download one of this workspace's files, an upload or a result, named as the person knows it. It works for an hour. Free.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"file_id":{"type":"string","description":"From list_files"}},"required":["file_id"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/look_at_files":{"post":{"operationId":"look_at_files","summary":"Look at files","description":"A quick look at a stack of files before reading them: what kind of document each is, how many pages, and the columns worth reading. Free. For Read documents into a table (read_fields). Use it to offer what to read before a run.","tags":["Files"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["read_fields"]},"file_ids":{"type":"array","items":{"type":"string"},"minItems":1}},"required":["action","file_ids"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/correct_transcript":{"post":{"operationId":"correct_transcript","summary":"Correct a transcript","description":"Saves a corrected copy of a finished transcription's words, free: one string per paragraph, in order, as the person wants them read. Words kept keep their times; the original stays; captions and conversions made afterwards use the corrected words.","tags":["Corrections"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"job_id":{"type":"string","description":"The transcription job, or a tool run that made one"},"paragraphs":{"type":"array","items":{"type":"string"},"minItems":1}},"required":["job_id","paragraphs"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/correct_table":{"post":{"operationId":"correct_table","summary":"Correct a table","description":"Corrects cells of a finished table, or adds a column read from its documents, free. Cells by row (from 0) and column key; the files made from the table, a spreadsheet made from it too, are written again with the corrections. The table as first made is kept.","tags":["Corrections"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"job_id":{"type":"string"},"cells":{"type":"array","items":{"type":"object","properties":{"row":{"type":"integer","minimum":0},"key":{"type":"string"},"value":{"type":"string"}},"required":["row","key","value"]}},"add":{"type":"array","items":{"type":"string"},"description":"Columns to add, by name"}},"required":["job_id"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/delete_file":{"post":{"operationId":"delete_file","summary":"Delete a file","description":"Deletes a file from this workspace straight away, freeing its room; identical copies go with it. The jobs and receipts stay. It cannot be undone, so ask the person first. A file a running job is reading is not deleted.","tags":["Files"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"file_id":{"type":"string"}},"required":["file_id"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/open_draft":{"post":{"operationId":"open_draft","summary":"Open a draft","description":"A draft, free: what was set on a tool's or action's page and not yet run, kept by Scrub as it was changed, to carry on where a person or an AI left off. Open it by its name (draft_…, from list_drafts or a save), or by tool and from, the job it was started from (a result's next step, or a run being changed); by tool alone, the person's latest draft of it. Gives its name, tool, title, params as the page holds them, the job it came from, when it was saved and its version. placed gives each timeline as it plays, in seconds: its length; its safe area in each aspect ratio (its top left corner, width and height as shares of the frame, null for none), where text boxes, logos and captions belong; each scene with its start, end and words as [word, start, end]; each text box with when it shows and where it is drawn in each aspect ratio (its middle, width and height as shares of the frame); each pause with the word it follows, where it begins, how long it was voiced and how long it plays; and each caption with its first and last word, when it shows, the words said, what it shows instead when set (shows), and whether it was set by hand.","tags":["Drafts"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"draft":{"type":"string","description":"Its name, draft_…"},"tool":{"type":"string","description":"The tool or action"},"from":{"type":"string","description":"The job it was started from, if any"}}}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/list_drafts":{"post":{"operationId":"list_drafts","summary":"List drafts","description":"A person's drafts, newest first, fifty at a time, free: what was set on a page and not yet run. Each with its name (draft_…), its tool, its own title (a script's title, the first words of an idea or a prompt, or the file it takes), when it was saved and the job it was started from. Give tool to list one tool's, words to find drafts with those words in them. total says how many match; when more is true, pass the last one's name as after for the next fifty.","tags":["Drafts"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tool":{"type":"string","description":"Only this tool’s or action’s drafts"},"words":{"type":"string","description":"Only drafts with these words in them"},"after":{"type":"string","description":"The next page: the drafts after this one"}}}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/save_draft":{"post":{"operationId":"save_draft","summary":"Save a draft","description":"Keeps what is set on a tool's or action's page before it runs, free, so the person opens it there as it was left, on any device: its params by name, each as text, a script as its JSON as open_draft gives it (a script that is not one is refused). Nothing runs. Give draft, the name a save or open_draft gave, to save over that draft; or from, the job it was started from, for that job's one draft; give neither to start a new draft, and its name is given back. Give the version you opened to save over only that one: if it was saved since, nothing is saved and the newer one's time is given. Empty params delete it. A person keeps up to 500 drafts.","tags":["Drafts"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tool":{"type":"string","description":"The tool or action"},"draft":{"type":"string","description":"Its name, draft_…, to save over it"},"from":{"type":"string","description":"The job it was started from, if any"},"params":{"type":"object","additionalProperties":true},"version":{"type":"integer","minimum":0}},"required":["tool","params"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/edit_draft":{"post":{"operationId":"edit_draft","summary":"Change part of a draft","description":"Changes part of a draft, free, without sending it all back: one pause, one caption line, one image. patch is JSON Patch (RFC 6902) on the draft's params by name: ops add, remove, replace and test, each {op, path, value}, applied in order, and a path goes into a param holding JSON, such as a script: /timeline/pauses/longest, /timeline/captions/lines/-, /timeline/scenes/2/line. Nothing runs. Give the version you opened to change only that one: if it was saved since, nothing changes and the newer one's time is given. If an op cannot be applied, a test does not hold, or a script no longer holds together, nothing changes and you are told why. placed gives each timeline as it plays, in seconds: its length; its safe area in each aspect ratio (its top left corner, width and height as shares of the frame, null for none), where text boxes, logos and captions belong; each scene with its start, end and words as [word, start, end]; each text box with when it shows and where it is drawn in each aspect ratio (its middle, width and height as shares of the frame); each pause with the word it follows, where it begins, how long it was voiced and how long it plays; and each caption with its first and last word, when it shows, the words said, what it shows instead when set (shows), and whether it was set by hand.","tags":["Drafts"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"draft":{"type":"string","description":"Its name, draft_…"},"patch":{"type":"array","description":"The changes, in order","items":{"type":"object","properties":{"op":{"type":"string","enum":["add","remove","replace","test"]},"path":{"type":"string"},"value":{}},"required":["op","path"]}},"version":{"type":"integer","minimum":0}},"required":["draft","patch"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/draft_history":{"post":{"operationId":"draft_history","summary":"See a draft’s history","description":"A draft's history, free: every version it was saved at, newest first, fifty at a time, each with when it was saved, who saved it (by: a tool page, Chat, the assistant, a connected AI by its name, an API key, a computer; none where it was not recorded), where (page, chat, assistant, mcp, api or computer) and how many changes made it from the version before. Give version to open that one as well: its params as open_draft gives them, and patch, its change from the version before as JSON Patch on the params. To go back to an earlier version, save its params over the draft with save_draft. total says how many versions there are; when more is true, pass the last one's version as before for the next fifty. placed gives each timeline as it plays, in seconds: its length; its safe area in each aspect ratio (its top left corner, width and height as shares of the frame, null for none), where text boxes, logos and captions belong; each scene with its start, end and words as [word, start, end]; each text box with when it shows and where it is drawn in each aspect ratio (its middle, width and height as shares of the frame); each pause with the word it follows, where it begins, how long it was voiced and how long it plays; and each caption with its first and last word, when it shows, the words said, what it shows instead when set (shows), and whether it was set by hand.","tags":["Drafts"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"draft":{"type":"string","description":"Its name, draft_…"},"version":{"type":"integer","minimum":1,"description":"A version to open"},"before":{"type":"integer","minimum":1,"description":"The next page: the versions before this one"}},"required":["draft"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/delete_draft":{"post":{"operationId":"delete_draft","summary":"Delete a draft","description":"Deletes a draft for good, by its name (draft_…): what was set on a page and not yet run. The runs made from it stay. It cannot be undone, so ask the person first.","tags":["Drafts"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"draft":{"type":"string","description":"Its name, draft_…"}},"required":["draft"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/list_flows":{"post":{"operationId":"list_flows","summary":"List flows","description":"This workspace's flows, newest saved first, free: what a person or an AI chained on the canvas from tools and actions. Each with its name (flow_…, the name it runs by, as any tool does), its title, its version, when it was saved and its steps by their names.","tags":["Flows"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/open_flow":{"post":{"operationId":"open_flow","summary":"Open a flow","description":"A flow, free, by its name (flow_…): its definition as save_flow takes it (its inputs, its settings and its steps, each running an action or one of Scrub's tools on the flow's inputs or an earlier step's result) and where its steps sit on the canvas. Its latest version, or an earlier one by version.","tags":["Flows"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"flow":{"type":"string","description":"Its name, flow_…"},"version":{"type":"integer","minimum":1,"description":"An earlier version"}},"required":["flow"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/save_flow":{"post":{"operationId":"save_flow","summary":"Save a flow","description":"Saves a flow, free: its title, its definition as open_flow gives it (inputs, params and steps; at most 20 steps), and where its steps sit. A step may be one of Scrub's tools ({id, tool, inputs, params, pass}): it runs as that tool is when the flow runs, its settings fixed by params, given each run by pass, or the tool's own. It is checked as a tool is: every step's inputs from the flow's inputs or an earlier step's result, every step priced by what is given before anything runs; one that would not run is not saved, and says why. A new flow is given its name (flow_…) and runs by that name, as any tool does, priced before it runs; its title changes freely. Saving one by its name keeps a new version; given version, it is saved only if that is still its latest.","tags":["Flows"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"flow":{"type":"string","description":"Its name, flow_…, to save a new version"},"title":{"type":"string","description":"What it is called"},"definition":{"type":"object","description":"Its inputs, params and steps, as open_flow gives them; its title, version, category and icon are filled in from its title and first step when left out.","properties":{"inputs":{"type":"object","description":"What it is given each run, by name: {\"src\": {\"type\": \"file\", \"label\": \"Video\", \"accept\": [\"video/*\"]}}"},"params":{"type":"object","description":"Settings given each run, by name, as a tool’s are"},"steps":{"type":"array","description":"What it does, in order","items":{"type":"object","properties":{"id":{"type":"string","description":"Its own short name: \"captions\""},"tool":{"type":"string","description":"One of Scrub's Tools, by its name or id: \"Caption a video\""},"action":{"type":"string","description":"Or an action, by its name or id as tools/list gives it: \"Compress a video\""},"inputs":{"type":"object","description":"Each input of its Tool or action, from the flow's inputs (\"src\") or an earlier step's result (\"captions.video\")"},"params":{"type":"object","description":"Its settings, fixed for every run"},"pass":{"type":"array","items":{"type":"string"},"description":"A Tool step's settings given each run, by name"}},"required":["id","inputs"]}}},"required":["steps"]},"layout":{"type":"object","description":"Where its steps sit on the canvas"},"version":{"type":"integer","minimum":1,"description":"The version it was opened at"}},"required":["title","definition"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/delete_flow":{"post":{"operationId":"delete_flow","summary":"Delete a flow","description":"Deletes a flow for good, by its name (flow_…): it no longer runs. Its runs stay. It cannot be undone, so ask the person first.","tags":["Flows"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"flow":{"type":"string","description":"Its name, flow_…"}},"required":["flow"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/list_brand_kits":{"post":{"operationId":"list_brand_kits","summary":"List Brand Kits","description":"This workspace's Brand Kits, by name, free: the look a person keeps for their videos. Each with its id (kit_…), its name and its parts, which are a timeline's own: brand {back, text, accent, font}, captions, safe, voice, music {prompt}, and logo {src, box?}, an image shown from the first scene to the last. To put a kit on a video, write its parts into the video's timeline: brand, captions and safe over the video's own, voice as given, music only where the video has none made, and the logo as an image with id kit-logo from the first scene's start until the last scene's end.","tags":["Brand Kits"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/save_brand_kit":{"post":{"operationId":"save_brand_kit","summary":"Save a Brand Kit","description":"Saves a Brand Kit, free: its name and its parts, each as a timeline has it (brand {back, text, accent, font}, captions, safe, voice, music {prompt}, logo {src: a file_id, box?}), checked as a timeline checks them; one that is not right is not saved, and says why. A new kit is given its id (kit_…); saving one by its id saves over it. A workspace keeps at most 50.","tags":["Brand Kits"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kit":{"type":"string","description":"Its id, kit_…, to save over it"},"name":{"type":"string","description":"What it is called"},"parts":{"type":"object","description":"Its parts, as a timeline has them"}},"required":["name","parts"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/delete_brand_kit":{"post":{"operationId":"delete_brand_kit","summary":"Delete a Brand Kit","description":"Deletes a Brand Kit for good, by its id (kit_…). Videos made with it keep their look. It cannot be undone, so ask the person first.","tags":["Brand Kits"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kit":{"type":"string","description":"Its id, kit_…"}},"required":["kit"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/profile_status":{"post":{"operationId":"profile_status","summary":"About you","description":"What this workspace said about itself after signing up: work or personal, the first thing they wanted done, what describes them, team size, company, how they heard of Scrub, and whether they want product news. Each may be unanswered. Free.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/set_profile":{"post":{"operationId":"set_profile","summary":"Change about you","description":"Changes what this workspace says about itself: any of the answers below, each left as it is when not given, cleared with an empty string. Product news is a yes only when the person said yes to its words. Free.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"use":{"type":"string","enum":["work","personal",""],"description":"Is Scrub for work or personal use? work (Work), personal (Personal)"},"first_job":{"type":"string","enum":["videos","recordings","documents","building","other",""],"description":"What do you want to get done first? videos (Videos and voiceovers), recordings (Recordings into text), documents (Receipts, invoices and documents), building (Building with AI), other (Something else)"},"first_job_other":{"type":"string","maxLength":80,"description":"With first_job other: what, in a few words."},"role":{"type":"string","enum":["freelancer","small_business","creator","developer","bookkeeping","other",""],"description":"What describes you best? freelancer (Freelancer or agency), small_business (Small business), creator (Creator or podcaster), developer (Developer or AI builder), bookkeeping (Bookkeeping or admin), other (Something else)"},"role_other":{"type":"string","maxLength":60,"description":"With role other: what they do, in a few words."},"team":{"type":"string","enum":["1","2-10","11-50","51+",""],"description":"How big is your team? Work only. 1 (Just me), 2-10 (2–10), 11-50 (11–50), 51+ (51+)"},"company":{"type":"string","maxLength":120,"description":"What is your company called? Work only."},"heard":{"type":"string","enum":["ai","friend","search","social","media","other",""],"description":"How did you hear about Scrub? ai (My AI suggested it), friend (A friend or colleague), search (Search), social (Social media), media (A newsletter, podcast or video), other (Something else)"},"product_news":{"type":"boolean","description":"Whether they want product news by email. true only when the person says yes to these words: \"Send me product news. Now and then. Unsubscribe from any email.\""},"questions":{"type":"string","enum":["shown","answered","skipped"],"description":"Where the questions after sign-up stand: shown, answered, or skipped. Once answered or skipped they are not asked again."}}}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/plan_status":{"post":{"operationId":"plan_status","summary":"Plan status","description":"This workspace's plan: Free with its balance, or a paid plan with how much of this month's work is left, when it renews, and whether additional usage is on. With the plans offered. Every price is the same on a plan; a paid plan buys a month of work for less. Free to call.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/set_additional_usage":{"post":{"operationId":"set_additional_usage","summary":"Set additional usage","description":"On a plan: whether the workspace's credit pays once the month's work is used up (on), or nothing more is spent until it renews (off). Off by default. Free; turning it on waits for the person's yes.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"on":{"type":"boolean","description":"true to let credit pay past the month."}},"required":["on"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/choose_plan":{"post":{"operationId":"choose_plan","summary":"Choose a plan","description":"A Stripe page where the person starts a paid plan, or changes to the other one: it starts at once, and the month already paid is kept until it runs out. Give them the link; the plan starts when they pay. Free is every workspace without a paid plan, never bought: ending a plan on manage_plan returns to it. Free to ask; the plan's price is on the page.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"plan":{"type":"string","enum":["pro","max"],"description":"pro: Pro, $20 a month for $25 of work; max: Max, $100 a month for $140 of work"}},"required":["plan"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/add_credit":{"post":{"operationId":"add_credit","summary":"Add credit","description":"A Stripe page where the person adds credit to pay as they go, as Account's Add credit does: $20, $50, $100, or any whole amount from $5 to $500. Credit never expires; on a plan, a top-up buys more work at the plan's rate. Give them the link; the credit lands when they pay. Free to ask.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"usd":{"type":"integer","minimum":5,"maximum":500,"description":"How much, in US dollars"}},"required":["usd"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/manage_plan":{"post":{"operationId":"manage_plan","summary":"Manage the plan","description":"Stripe's billing page for this workspace's plan: its card, its invoices, and ending it, which happens when the month paid for ends. Give the person the link. Free.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/send_feedback":{"post":{"operationId":"send_feedback","summary":"Send feedback","description":"Sends the Scrub team a problem the person met, or an idea for Scrub, in their own words, as they ask. A problem: something broken, wrong or confusing; give job_id when it is about one job. Files: screenshots, images, or a screen recording of up to 30 seconds with their voice. Only when the person asks to send something. Free. Up to 20 a day.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["problem","idea"],"description":"A problem, or an idea"},"subject":{"type":"string","description":"A short summary, in their words","maxLength":120},"said":{"type":"string","description":"What happened, or what they want, in their own words: what they did, expected and saw, or what they are trying to get done","maxLength":4000},"job_id":{"type":"string","description":"The job it is about, such as job_3f9a1c2b7d4e, when it is about one"},"links":{"type":"array","items":{"type":"string"},"maxItems":5,"description":"Web addresses it is about"},"files":{"type":"array","maxItems":5,"description":"Screenshots, images or a short clip, each as base64","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","enum":["image/png","image/jpeg","image/webp","video/webm","video/mp4"]},"data":{"type":"string","description":"The file, base64"}},"required":["type","data"]}},"context":{"type":"string","description":"What the page knew, for the founder only: where, the browser, errors","maxLength":3000}},"required":["kind","said"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/list_updates":{"post":{"operationId":"list_updates","summary":"Product updates","description":"What Scrub has made live, has in beta, is building, plans and is considering, newest moves first: each with its stage, its area, the words written for people in parts (summary, sections, a dated note at each step, a picture or video), what it ships to try, the tools and actions it is about by id, and whether this workspace follows it, asked for it, joined its beta, or has not seen it. seen: true marks them all seen. Free.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"stage":{"type":"string","enum":["live","beta","dev","planned","idea","no","retired"],"description":"Only this stage"},"seen":{"type":"boolean","description":"Mark every update seen, as opening Product updates does"}}}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/follow_update":{"post":{"operationId":"follow_update","summary":"Follow an update","description":"Follows a product update, by its id as list_updates gives it: the person is emailed when it moves stage, and the founder sees that they want it. on: false stops following. Free.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"update":{"type":"string","description":"The update’s id, as list_updates gives it"},"on":{"type":"boolean","description":"false to stop following"}},"required":["update"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/join_beta":{"post":{"operationId":"join_beta","summary":"Join a beta","description":"Joins the beta of a product update that is In beta, by its id as list_updates gives it: what it ships runs for this workspace before everyone, in every place Scrub is used, and the workspace follows it, so it hears when it moves. The founder sees who joined. on: false leaves the beta. Free.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"update":{"type":"string","description":"The update’s id, as list_updates gives it"},"on":{"type":"boolean","description":"false to leave the beta"}},"required":["update"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/search_help":{"post":{"operationId":"search_help","summary":"Search Scrub’s help","description":"Scrub’s own help: a guide for each part of Scrub (getting started, plans and credit, connecting an AI, what is charged when work stops, Flows) and an article for every Tool and Action, with its price. Answer a question about how Scrub works from these, and say which article it came from. Empty words list every article. Free.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"q":{"type":"string","description":"Words to look for, or the person’s own question, such as refund or how do I get my money back"}}}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/message_support":{"post":{"operationId":"message_support","summary":"Message the Scrub team","description":"Sends the person's message to the founder of Scrub, who answers in person: live while answering, otherwise replies by email within a day. For what Scrub's help and its tools cannot answer, or when the person asks for a person. Give carried: what they asked Scrub before, and the job it is about, so they are not asked twice. Only with the person's yes. Free.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"said":{"type":"string","description":"Their message, in their words","maxLength":4000},"carried":{"type":"string","description":"What went before: what they asked Scrub and what it said, and the job, such as job_3f9a1c2b7d4e","maxLength":4000}},"required":["said"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/support_conversation":{"post":{"operationId":"support_conversation","summary":"Your conversation with Scrub","description":"The person's conversation with the founder of Scrub, newest last, whether the founder is answering now, and how many replies they have not seen. Reading it marks the replies seen. Free.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{},"required":[]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/connect_steps":{"post":{"operationId":"connect_steps","summary":"Connect an AI to Scrub","description":"How a person adds Scrub to an AI they use, step by step, with the address or command to paste. Free. Give ai for one AI's steps, or nothing for every one. The AIs: Claude (claude), Claude Code (claude-code), Another AI (other). For any other AI, give other. asks are things to ask once it is connected.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ai":{"type":"string","enum":["claude","claude-code","other"],"description":"Which AI"}}}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/list_connections":{"post":{"operationId":"list_connections","summary":"List connected AIs","description":"The AIs connected to this workspace and not disconnected, newest first: each with its name, where it connected from, since when and when it was last used. Free. A person disconnects one in Account.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/list_computers":{"post":{"operationId":"list_computers","summary":"List computers","description":"The computers running the Scrub app for this workspace, the one seen last first: each with its own name, the app and its version, whether it is open to take work now, when it was last seen and since when, and the files the person gave Scrub there (the latest 20), by name, size and length. Free. Give a file's file_id (cf_…) to an action that runs on a computer to run it there, while the app is open; send it to Files with add_computer_file for anything else. A run on a computer is listed in Jobs like any job, under the computer's name.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":true,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/remove_computer":{"post":{"operationId":"remove_computer","summary":"Remove a computer","description":"Removes a computer from this workspace, free: the Scrub app on it is signed out and records no more work there. Its jobs stay. Signing in again adds it back. Ask the person first.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"computer_id":{"type":"string","description":"pc_…, from list_computers"}},"required":["computer_id"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/add_computer_file":{"post":{"operationId":"add_computer_file","summary":"Add a file from a computer to Files","description":"Sends a file the person gave Scrub on a computer (cf_…, from list_computers) to Files, from the Scrub app there, while it is open. Free. Answers its file_id when it has arrived; a large file may still be on its way, so check list_computers, where it shows in Files once there. A file sent before and unchanged is not sent again. Then give the file_id to any tool.","tags":["Prices and jobs"],"x-scrub-priced":false,"x-scrub-read-only":false,"security":[{"key":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Send the same key again and the same job is found rather than a second one charged.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"file_id":{"type":"string","description":"cf_…, from list_computers"}},"required":["file_id"]}}}},"responses":{"200":{"description":"Done, or started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Result"}}}},"400":{"description":"The body is not a JSON object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or a wrong one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused, and not charged: the reason says why","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls this minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}