{"openapi":"3.0.3","info":{"title":"Morrow","version":"1.2.0","description":"Persistent, fingerprint-resistant browser profiles with a browserless-style HTTP API.\n\nEvery endpoint except `/health` and `/openapi.json` requires the API key, either as\n`Authorization: Bearer <key>` or as a `?token=<key>` query parameter (for WebSocket clients).\n\nThe Playwright attach endpoint (`ws://<host>/playwright?profile=<name>&token=<key>`) is a WebSocket\npassthrough and therefore not described here."},"servers":[{"url":"/api/v1"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Profiles","description":"Create, inspect and manage persistent browser profiles."},{"name":"Lifecycle","description":"Start, stop, clone and reset a profile's browser."},{"name":"Scrape","description":"Browserless-style extraction: content, screenshot, scrape."},{"name":"Ops","description":"Health, capacity and active sessions."}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"The Morrow API key (`MORROW_API_KEY`)."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}},"required":["error"]},"Session":{"type":"object","properties":{"id":{"type":"string"},"profileId":{"type":"string"},"profileName":{"type":"string"},"kind":{"type":"string","enum":["playwright","viewer","mcp","scrape"]},"connectedAt":{"type":"string"},"disconnectedAt":{"type":"string","nullable":true}},"required":["id","profileId","profileName","kind","connectedAt","disconnectedAt"]},"Profile":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["stopped","starting","running","stopping","error"]},"proxy":{"type":"string","nullable":true},"locale":{"type":"string","nullable":true},"timezone":{"type":"string","nullable":true},"viewport":{"type":"object","nullable":true,"properties":{"width":{"type":"integer"},"height":{"type":"integer"}},"required":["width","height"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","status","proxy","locale","timezone","viewport","createdAt","updatedAt"]},"Event":{"type":"object","properties":{"id":{"type":"integer"},"profileId":{"type":"string","nullable":true},"type":{"type":"string"},"data":{"nullable":true},"createdAt":{"type":"string"}},"required":["id","profileId","type","createdAt"]},"ScrapeResult":{"type":"object","properties":{"url":{"type":"string"},"markdown":{"type":"string"},"text":{"type":"string","nullable":true},"article":{"type":"object","properties":{"title":{"type":"string","nullable":true},"byline":{"type":"string","nullable":true},"excerpt":{"type":"string","nullable":true},"content":{"type":"string","nullable":true,"description":"Readability-cleaned HTML"},"text":{"type":"string","nullable":true},"markdown":{"type":"string"}},"required":["title","byline","excerpt","content","text","markdown"]},"elements":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["url"]}},"parameters":{}},"paths":{"/health":{"get":{"tags":["Ops"],"summary":"Liveness probe","security":[],"responses":{"200":{"description":"Service is up","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"version":{"type":"string"}},"required":["ok","version"]}}}}}}},"/openapi.json":{"get":{"tags":["Ops"],"summary":"This document","security":[],"responses":{"200":{"description":"OpenAPI 3 document","content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":{"nullable":true}}}}}}}},"/pressure":{"get":{"tags":["Ops"],"summary":"Capacity and load","responses":{"200":{"description":"Current pressure","content":{"application/json":{"schema":{"type":"object","properties":{"runningProfiles":{"type":"integer"},"maxProfiles":{"type":"integer"},"memory":{"type":"integer","description":"Resident set size in bytes"},"queued":{"type":"integer"}},"required":["runningProfiles","maxProfiles","memory","queued"]}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sessions":{"get":{"tags":["Ops"],"summary":"List active sessions","responses":{"200":{"description":"Active sessions","content":{"application/json":{"schema":{"type":"object","properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/Session"}}},"required":["sessions"]}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/profiles":{"get":{"tags":["Profiles"],"summary":"List profiles","responses":{"200":{"description":"All profiles","content":{"application/json":{"schema":{"type":"object","properties":{"profiles":{"type":"array","items":{"$ref":"#/components/schemas/Profile"}}},"required":["profiles"]}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Profiles"],"summary":"Create a profile","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,62}$"},"proxy":{"type":"string","minLength":1},"locale":{"type":"string","minLength":2},"timezone":{"type":"string","minLength":1},"viewport":{"type":"object","properties":{"width":{"type":"integer","minimum":0,"exclusiveMinimum":true},"height":{"type":"integer","minimum":0,"exclusiveMinimum":true}},"required":["width","height"]}},"required":["name"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Profile is running, busy, or the name is taken","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/profiles/{name}":{"get":{"tags":["Profiles"],"summary":"Get a profile","parameters":[{"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,62}$","description":"Profile name"},"required":true,"description":"Profile name","name":"name","in":"path"}],"responses":{"200":{"description":"The profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Profiles"],"summary":"Update a profile","parameters":[{"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,62}$","description":"Profile name"},"required":true,"description":"Profile name","name":"name","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"proxy":{"type":"string","nullable":true,"minLength":1},"locale":{"type":"string","nullable":true,"minLength":2},"timezone":{"type":"string","nullable":true,"minLength":1},"viewport":{"type":"object","properties":{"width":{"type":"integer","minimum":0,"exclusiveMinimum":true},"height":{"type":"integer","minimum":0,"exclusiveMinimum":true}},"required":["width","height"]}}}}}},"responses":{"200":{"description":"The updated profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Profiles"],"summary":"Delete a profile and its browser data","parameters":[{"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,62}$","description":"Profile name"},"required":true,"description":"Profile name","name":"name","in":"path"}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Profile is running, busy, or the name is taken","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/profiles/{name}/events":{"get":{"tags":["Profiles"],"summary":"Recent profile events","parameters":[{"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,62}$","description":"Profile name"},"required":true,"description":"Profile name","name":"name","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":1000,"description":"Default 200"},"required":false,"description":"Default 200","name":"limit","in":"query"}],"responses":{"200":{"description":"Events, oldest first","content":{"application/json":{"schema":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/Event"}}},"required":["events"]}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/profiles/{name}/start":{"post":{"tags":["Lifecycle"],"summary":"Start the profile's browser","parameters":[{"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,62}$","description":"Profile name"},"required":true,"description":"Profile name","name":"name","in":"path"}],"responses":{"200":{"description":"The profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Profile is running, busy, or the name is taken","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/profiles/{name}/stop":{"post":{"tags":["Lifecycle"],"summary":"Stop the profile's browser","parameters":[{"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,62}$","description":"Profile name"},"required":true,"description":"Profile name","name":"name","in":"path"}],"responses":{"200":{"description":"The profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Profile is running, busy, or the name is taken","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/profiles/{name}/reset":{"post":{"tags":["Lifecycle"],"summary":"Wipe the profile's browser data (cookies, storage, cache)","parameters":[{"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,62}$","description":"Profile name"},"required":true,"description":"Profile name","name":"name","in":"path"}],"responses":{"200":{"description":"The profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Profile is running, busy, or the name is taken","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/profiles/{name}/clone":{"post":{"tags":["Lifecycle"],"summary":"Copy a stopped profile, browser data included","parameters":[{"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,62}$","description":"Profile name"},"required":true,"description":"Profile name","name":"name","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,62}$"}},"required":["name"]}}}},"responses":{"201":{"description":"The clone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Profile is running, busy, or the name is taken","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/content":{"post":{"tags":["Scrape"],"summary":"Fully rendered HTML of a page","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"html":{"type":"string"},"profile":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,62}$"},"gotoOptions":{"type":"object","properties":{"waitUntil":{"type":"string","enum":["load","domcontentloaded","networkidle","commit"]},"timeout":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":120000}}},"waitForSelector":{"type":"object","properties":{"selector":{"type":"string","minLength":1},"timeout":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":120000}},"required":["selector"]},"waitForTimeout":{"type":"integer","minimum":0,"maximum":60000},"waitForFunction":{"type":"object","properties":{"fn":{"type":"string","minLength":1},"timeout":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":120000}},"required":["fn"]},"bestAttempt":{"type":"boolean"},"viewport":{"type":"object","properties":{"width":{"type":"integer","minimum":0,"exclusiveMinimum":true},"height":{"type":"integer","minimum":0,"exclusiveMinimum":true}},"required":["width","height"]},"rejectResourceTypes":{"type":"array","items":{"type":"string"}},"rejectRequestPattern":{"type":"array","items":{"type":"string"}},"setExtraHTTPHeaders":{"type":"object","additionalProperties":{"type":"string"}}}}}}},"responses":{"200":{"description":"Page HTML","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/screenshot":{"post":{"tags":["Scrape"],"summary":"Screenshot a page or a single element","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"html":{"type":"string"},"profile":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,62}$"},"gotoOptions":{"type":"object","properties":{"waitUntil":{"type":"string","enum":["load","domcontentloaded","networkidle","commit"]},"timeout":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":120000}}},"waitForSelector":{"type":"object","properties":{"selector":{"type":"string","minLength":1},"timeout":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":120000}},"required":["selector"]},"waitForTimeout":{"type":"integer","minimum":0,"maximum":60000},"waitForFunction":{"type":"object","properties":{"fn":{"type":"string","minLength":1},"timeout":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":120000}},"required":["fn"]},"bestAttempt":{"type":"boolean"},"viewport":{"type":"object","properties":{"width":{"type":"integer","minimum":0,"exclusiveMinimum":true},"height":{"type":"integer","minimum":0,"exclusiveMinimum":true}},"required":["width","height"]},"rejectResourceTypes":{"type":"array","items":{"type":"string"}},"rejectRequestPattern":{"type":"array","items":{"type":"string"}},"setExtraHTTPHeaders":{"type":"object","additionalProperties":{"type":"string"}},"fullPage":{"type":"boolean"},"type":{"type":"string","enum":["png","jpeg"]},"quality":{"type":"integer","minimum":0,"maximum":100},"selector":{"type":"string","minLength":1}}}}}},"responses":{"200":{"description":"Image bytes","content":{"image/png":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/scrape":{"post":{"tags":["Scrape"],"summary":"Extract markdown, plain text, a readability article and/or selector matches","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"html":{"type":"string"},"profile":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,62}$"},"gotoOptions":{"type":"object","properties":{"waitUntil":{"type":"string","enum":["load","domcontentloaded","networkidle","commit"]},"timeout":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":120000}}},"waitForSelector":{"type":"object","properties":{"selector":{"type":"string","minLength":1},"timeout":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":120000}},"required":["selector"]},"waitForTimeout":{"type":"integer","minimum":0,"maximum":60000},"waitForFunction":{"type":"object","properties":{"fn":{"type":"string","minLength":1},"timeout":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":120000}},"required":["fn"]},"bestAttempt":{"type":"boolean"},"viewport":{"type":"object","properties":{"width":{"type":"integer","minimum":0,"exclusiveMinimum":true},"height":{"type":"integer","minimum":0,"exclusiveMinimum":true}},"required":["width","height"]},"rejectResourceTypes":{"type":"array","items":{"type":"string"}},"rejectRequestPattern":{"type":"array","items":{"type":"string"}},"setExtraHTTPHeaders":{"type":"object","additionalProperties":{"type":"string"}},"format":{"type":"string","enum":["markdown","text","article"],"default":"markdown"},"elements":{"type":"array","items":{"type":"object","properties":{"selector":{"type":"string","minLength":1}},"required":["selector"]}}}}}}},"responses":{"200":{"description":"Extraction result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScrapeResult"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}