{"openapi":"3.1.0","info":{"title":"Tarkle API","version":"v1","summary":"Brands, files, uploads and storage usage for Tarkle workspaces","description":"Public API for Tarkle workspaces: brands, files and folders, uploads, storage usage and the workspaces a token can reach.\n\n**Start.** Create a token in Settings > API and send it as `Authorization: Bearer tk_...`. A token works for every workspace its creator can use. Call GET /workspaces to list them, then send the workspace's 8-character key in the `X-Workspace-Key` header (or the `workspace_key` query parameter) on every other call.\n\n**Scopes.** `brands:read` (Read brands, their assets, brand.md and analytics); `brands:write` (Update a brand's text, links, access and settings); `brands:create` (Create brands, delete them to the bin and restore them from it); `brands:requests` (List download and view requests and approve or reject them); `webhooks:manage` (Add, change and remove webhook endpoints, send test events and read the delivery log); `files:read` (List and download files and folders); `files:write` (Create folders, rename and delete files and folders (and restore them from the bin); uploads are separate endpoints). Each operation lists the scope it needs in `x-required-scope`.\n\n**Rate limits.** Brand operations allow 120 requests a minute per token; files operations and GET /workspaces allow 600. These are working values: read the limit from `X-RateLimit-Limit` rather than hard-coding it. Every authenticated response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` (Unix seconds). A 429 adds `Retry-After` (seconds).\n\n**Errors.** Every error is a problem details object (RFC 9457) with the content type `application/problem+json`: `type`, `title`, `status`, `detail` and a stable `code` to branch on. The older `error: { code, message }` envelope is still included. `x-error-codes` lists every code with its status and meaning.\n\n**Safe repeats.** Send `Idempotency-Key` (any random value up to 255 characters) with a POST, PATCH, PUT or DELETE and a repeat of the same request returns the first answer instead of doing it twice. See the header's description for the rules.\n\n**Versioning.** The version is in the path (`/api/v1`). Inside v1 we only add things: endpoints, optional parameters, response fields and error codes, so ignore fields and codes you do not know. A change that could break a client ships as a new version, and the old one keeps working for at least 6 months after we announce its end, with `Deprecation` and `Sunset` headers on its responses during that time.\n\nGuides and examples: https://tarkle.com/docs/api/brands","termsOfService":"https://tarkle.com/terms","contact":{"name":"Tarkle support","email":"support@tarkle.com","url":"https://tarkle.com/contact"}},"externalDocs":{"description":"Tarkle API guides","url":"https://tarkle.com/docs/api/brands"},"servers":[{"url":"https://tarkle.com/api/v1"}],"tags":[{"name":"Brands","description":"Read and update brand pages, their assets, brand.md and analytics. The token's creator must be an owner or admin of the workspace."},{"name":"Requests","description":"Download and view requests people send from a brand page, and your decision on them."},{"name":"Webhooks","description":"Tarkle sends signed events to addresses you register. Each delivery is a POST of the WebhookEvent object with the headers Tarkle-Signature (t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" with your endpoint's secret>, one v1 per secret in force), Tarkle-Event, Tarkle-Event-Id and Tarkle-Delivery. Check the signature on the raw body and reject a timestamp more than 5 minutes old. Events: brand.viewed (only when an endpoint names it; \"all events\" does not include page views), brand.downloaded (the file, never the visitor), brand.updated (the names of what changed), brand.request.created, brand.request.approved and brand.request.rejected (who asked: name, company, email). Answer with any 2xx within 10 seconds. Otherwise Tarkle retries up to 8 times over about 24 hours; an endpoint that keeps failing is switched off and the owner is emailed. Redirects are not followed and addresses on private networks are refused. The token's creator must be an owner or admin of the workspace."},{"name":"Files","description":"The workspace library: list, read, download, create folders, rename, move, copy, delete and restore; uploads, including multipart; storage usage; and the workspaces a token can act on."}],"components":{"schemas":{"Problem":{"type":"object","description":"A problem details object (RFC 9457), sent as application/problem+json on every error. Branch on code, not on detail: code is stable, detail is for people and can change.","properties":{"type":{"type":"string","format":"uri","description":"Identifies the problem: https://tarkle.com/docs/api/errors/<code>. Treat it as an identifier"},"title":{"type":"string","description":"A short, fixed summary of the problem type"},"status":{"type":"integer","description":"The HTTP status code, repeated for clients that lose the response line"},"detail":{"type":"string","description":"What went wrong this time, in plain words"},"code":{"type":"string","description":"A stable machine-readable code such as not_found or name_taken. Every code is listed in x-error-codes. v1 can add codes, so treat one you do not know by its HTTP status"},"details":{"type":"object","additionalProperties":true,"description":"Extra members for some codes; x-details-by-code says which schema each uses"},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"object","additionalProperties":true}},"required":["code","message"],"description":"The envelope older clients read: the same code, with detail as message. Prefer the top-level members"}},"required":["type","title","status","detail","code","error"],"x-details-by-code":{"conflict":{"$ref":"#/components/schemas/ConflictDetails"},"empty_version_not_supported":{"$ref":"#/components/schemas/ChoicesDetails"},"incomplete":{"$ref":"#/components/schemas/IncompleteDetails"},"transfer_active":{"$ref":"#/components/schemas/TransferActiveDetails"},"protected":{"$ref":"#/components/schemas/ProtectedDetails"}}},"ConflictDetails":{"type":"object","properties":{"reason":{"type":["string","null"],"description":"Why the app would ask, for example file_in_transfer"},"existing":{"oneOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]},{"type":"null"}],"description":"The file that holds the name"},"answer_with":{"type":"string","enum":["on_conflict"],"description":"The request field that carries your answer"},"choices":{"type":"array","items":{"type":"string","enum":["version","separate","skip"]}}},"required":["reason","existing","answer_with","choices"]},"ChoicesDetails":{"type":"object","properties":{"choices":{"type":"array","items":{"type":"string","enum":["separate","skip"]}}},"required":["choices"]},"IncompleteDetails":{"type":"object","properties":{"parts_received":{"type":"integer"},"parts_needed":{"type":"integer"},"missing_parts":{"type":"array","items":{"type":"integer"},"description":"The part numbers still to send (at most 1000 are listed)"},"missing_parts_truncated":{"type":"boolean","description":"Present and true when more parts are missing than listed"}},"required":["parts_received","parts_needed","missing_parts"]},"TransferRef":{"type":"object","properties":{"id":{"type":"integer"},"type":{"type":"string"},"title":{"type":["string","null"]}},"required":["id"]},"TransferActiveDetails":{"type":"object","properties":{"transfers":{"type":"array","items":{"$ref":"#/components/schemas/TransferRef"}},"needs_confirmation":{"type":"boolean","description":"True when repeating the call with the confirmation would delete those transfers"},"needs_token_setting":{"type":"boolean","description":"True when the token's settings do not allow deleting transfers"},"confirm_with":{"type":"string","description":"The query parameter that confirms the delete"}},"required":["transfers","needs_confirmation","needs_token_setting","confirm_with"]},"ProtectedDetails":{"type":"object","properties":{"kind":{"type":["string","null"]},"transfers":{"type":"array","items":{"$ref":"#/components/schemas/TransferRef"}}},"required":["kind"]},"BrandSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"name":{"type":"string"},"summary":{"type":"string"},"access":{"type":"string","enum":["public","password","restricted"],"description":"public: anyone; password: anyone with the password; restricted: only people assigned to the brand"},"is_draft":{"type":"boolean"},"download_approval":{"type":"boolean"},"indexable":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"urls":{"type":"object","properties":{"page":{"type":"string"},"api":{"type":"string"}},"required":["page","api"]}},"required":["id","slug","name","summary","access","is_draft","download_approval","indexable","created_at","urls"]},"BrandList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BrandSummary"}},"next_cursor":{"type":["string","null"],"description":"Pass as ?cursor= for the next page; null on the last page. Opaque: do not build or parse it."}},"required":["data","next_cursor"]},"Brand":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"name":{"type":"string"},"summary":{"type":"string"},"story":{"type":"string"},"industry":{"type":"string"},"size":{"type":"string"},"company_type":{"type":"string"},"year_founded":{"type":"string"},"website":{"type":"string"},"social":{"type":"object","properties":{"twitter":{"type":"string"},"facebook":{"type":"string"},"instagram":{"type":"string"},"linkedin":{"type":"string"},"youtube":{"type":"string"},"github":{"type":"string"}},"required":["twitter","facebook","instagram","linkedin","youtube","github"]},"colors":{"type":"object","properties":{"primary":{"type":["string","null"]},"secondary":{"type":["string","null"]},"additional":{"type":"array","items":{"type":"object","properties":{"name":{"type":["string","null"]},"value":{"type":"string"}},"required":["name","value"]}}},"required":["primary","secondary","additional"]},"fonts":{"type":"object","properties":{"headline":{"oneOf":[{"type":"null"},{"type":"object","properties":{"name":{"type":"string"},"custom":{"type":"boolean"}},"required":["name","custom"]}]},"body":{"oneOf":[{"type":"null"},{"type":"object","properties":{"name":{"type":"string"},"custom":{"type":"boolean"}},"required":["name","custom"]}]}},"required":["headline","body"]},"access":{"type":"string","enum":["public","password","restricted"],"description":"public: anyone; password: anyone with the password; restricted: only people assigned to the brand"},"is_draft":{"type":"boolean"},"download_approval":{"type":"boolean"},"indexable":{"type":"boolean"},"tracking":{"type":"object","properties":{"ga4":{"type":"string"},"gtm":{"type":"string"},"search_console":{"type":"string"},"adobe_kit":{"type":"string"}},"required":["ga4","gtm","search_console","adobe_kit"]},"seo":{"type":"object","properties":{"title":{"type":["string","null"]},"description":{"type":["string","null"]}},"required":["title","description"]},"team":{"type":"object","properties":{"title":{"type":"string"},"members":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"title":{"type":"string"}},"required":["name","title"]}}},"required":["title","members"]},"press":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"url":{"type":"string"},"source":{"type":"string"}},"required":["title","url","source"]}},"urls":{"type":"object","properties":{"page":{"type":"string"},"markdown":{"type":"string"},"mark_usage":{"type":"string"},"api":{"type":"string"}},"required":["page","markdown","mark_usage","api"]},"created_at":{"type":"string","format":"date-time"}},"required":["id","slug","name","summary","story","industry","size","company_type","year_founded","website","social","colors","fonts","access","is_draft","download_approval","indexable","tracking","seo","team","press","urls","created_at"]},"BrandCreate":{"type":"object","additionalProperties":false,"required":["name"],"description":"Text limits are the app's (name 48, summary 200, story 2000 characters); longer values are refused. A new brand is a private draft. access, is_draft and confirm_public are not accepted here; use updateBrand afterwards.","properties":{"name":{"type":"string","minLength":1,"maxLength":48},"slug":{"type":"string","maxLength":48,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$","description":"Defaults to the name"},"summary":{"type":"string","maxLength":200},"story":{"type":"string","maxLength":2000},"industry":{"type":"string","maxLength":80},"size":{"type":"string","maxLength":80},"company_type":{"type":"string","maxLength":80},"year_founded":{"type":["string","integer"]},"url":{"type":"string"},"twitter":{"type":"string"},"facebook":{"type":"string"},"instagram":{"type":"string"},"linkedin":{"type":"string"},"youtube":{"type":"string"},"github":{"type":"string"},"primary_color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"download_approval":{"type":"boolean"},"meta_title":{"type":"string","maxLength":160},"meta_description":{"type":"string","maxLength":320},"team_title":{"type":"string","maxLength":40},"tracking":{"type":"object","properties":{"ga4":{"type":"string"},"gtm":{"type":"string"},"search_console":{"type":"string"},"adobe_kit":{"type":"string"}},"additionalProperties":false}}},"DeletedBrand":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"name":{"type":"string"},"deleted_at":{"type":"string","format":"date-time"},"restorable_until":{"type":["string","null"],"format":"date-time"},"domains":{"type":"array","items":{"type":"string"}}},"required":["id","slug","name","deleted_at","restorable_until","domains"]},"DeletedBrandList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DeletedBrand"}}},"required":["data"]},"BrandRestore":{"type":"object","additionalProperties":false,"properties":{"slug":{"type":"string","maxLength":48,"description":"Another address, when the old one is used now"}}},"BrandPatch":{"type":"object","additionalProperties":false,"minProperties":1,"description":"Send only what changes. The slug, files, passwords and domains cannot be changed here. Making a brand public needs confirm_public: true.","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"summary":{"type":"string","maxLength":500},"story":{"type":"string","maxLength":6000},"industry":{"type":"string","maxLength":80},"size":{"type":"string","maxLength":80},"company_type":{"type":"string","maxLength":80},"year_founded":{"type":["string","integer"],"description":"A four digit year, or empty to clear"},"url":{"type":"string","description":"A public website address, or empty to clear"},"twitter":{"type":"string"},"facebook":{"type":"string"},"instagram":{"type":"string"},"linkedin":{"type":"string"},"youtube":{"type":"string"},"github":{"type":"string"},"primary_color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"access":{"type":"string","enum":["public","restricted"],"description":"public also removes the password. restricted needs a contact or organization assigned first"},"confirm_public":{"type":"boolean","description":"Must be true when access changes to public on a brand that is not public yet; otherwise the call is refused (400 confirmation_required)"},"download_approval":{"type":"boolean"},"is_draft":{"type":"boolean"},"meta_title":{"type":"string","maxLength":160},"meta_description":{"type":"string","maxLength":320},"team_title":{"type":"string","maxLength":40},"tracking":{"type":"object","properties":{"ga4":{"type":"string"},"gtm":{"type":"string"},"search_console":{"type":"string"},"adobe_kit":{"type":"string"}},"additionalProperties":false,"description":"Only the keys sent change"}}},"BrandAssets":{"type":"object","properties":{"brand":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"}},"required":["id","slug"]},"images":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string","enum":["icon","main_logo","banner"]},"name":{"type":"string"},"download_url":{"type":"string"}},"required":["role","name","download_url"]}},"logos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"type":{"type":["string","null"]},"download_url":{"type":"string"}},"required":["id","name","type","download_url"]}},"collections":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"files":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"type":{"type":["string","null"]},"size":{"type":["string","null"]},"download_url":{"type":"string"}},"required":["id","name","type","size","download_url"]}}},"required":["id","name","description","files"]}},"links_expire":{"type":"boolean","description":"Always true: the download links are short-lived; list again for fresh ones"}},"required":["brand","images","logos","collections","links_expire"]},"Series":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string"},"count":{"type":"integer"}},"required":["date"]}},"BrandAnalytics":{"type":"object","properties":{"period":{"type":"string","enum":["30d","90d","all"]},"views":{"type":"object","properties":{"total":{"type":"integer"},"series":{"$ref":"#/components/schemas/Series"}},"required":["total","series"]},"downloads":{"type":"object","properties":{"total":{"type":"integer"},"series":{"$ref":"#/components/schemas/Series"}},"required":["total","series"]},"requests":{"type":"object","properties":{"total":{"type":"integer"},"series":{"$ref":"#/components/schemas/Series"}},"required":["total","series"]},"downloaded_files":{"oneOf":[{"type":"null"},{"type":"object","properties":{"top_assets":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"count":{"type":"integer"}},"required":["name","count"]}},"formats":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"count":{"type":"integer"}},"required":["name","count"]}},"unrecorded":{"type":"integer"}},"required":["top_assets","formats","unrecorded"]}],"description":"The most downloaded files and the formats taken in the period; null until the file columns exist. Downloads from before files were recorded are counted in `unrecorded`."}},"required":["period","views","downloads","requests","downloaded_files"]},"WebhookEndpoint":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string"},"description":{"type":["string","null"]},"events":{"type":"array","items":{"type":"string"},"description":"The event types this endpoint receives, or [\"*\"] for every event"},"enabled":{"type":"boolean"},"disabled_reason":{"oneOf":[{"type":"null"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}],"description":"Why the endpoint is off: turned_off, no_success_for_5_days, deliveries_kept_failing or endpoint_gone"},"disabled_at":{"type":["string","null"],"format":"date-time"},"last_success_at":{"type":["string","null"],"format":"date-time"},"last_failure_at":{"type":["string","null"],"format":"date-time"},"failed_attempts_in_a_row":{"type":"integer"},"secret_rotation_ends_at":{"type":["string","null"],"format":"date-time","description":"While a rotated secret is still signing alongside the new one: when it stops"},"created_at":{"type":"string","format":"date-time"}},"required":["id","url","description","events","enabled","disabled_reason","disabled_at","last_success_at","last_failure_at","failed_attempts_in_a_row","secret_rotation_ends_at","created_at"]},"WebhookEndpointList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpoint"}}},"required":["data"]},"WebhookEndpointCreate":{"type":"object","properties":{"url":{"type":"string","description":"https only, a public name (no IP number, localhost or internal name), port 443 or 1024 and up, at most 2000 characters"},"events":{"type":"array","items":{"type":"string"},"description":"Event types to receive; omit for every event"},"description":{"type":["string","null"],"maxLength":200}},"required":["url"]},"WebhookEndpointUpdate":{"type":"object","description":"At least one field.","properties":{"url":{"type":"string"},"events":{"type":"array","items":{"type":"string"}},"description":{"type":["string","null"],"maxLength":200},"enabled":{"type":"boolean","description":"false stops deliveries; true starts them again and clears the failure count"}}},"WebhookEndpointCreated":{"type":"object","properties":{"endpoint":{"$ref":"#/components/schemas/WebhookEndpoint"},"secret":{"type":"string","description":"The signing secret (whsec_...). It is shown only now"}},"required":["endpoint","secret"]},"WebhookSecretRotated":{"type":"object","properties":{"secret":{"type":"string","description":"The new signing secret. It is shown only now"},"previous_secret_expires_at":{"type":"string","format":"date-time","description":"The old secret also signs until then"}},"required":["secret","previous_secret_expires_at"]},"WebhookDelivery":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"event_id":{"type":"string","description":"The id inside the event body; the same on every retry, so a receiver can ignore a repeat"},"event_type":{"type":"string"},"status":{"type":"string","enum":["pending","succeeded","failed"],"description":"pending: waiting for a try; failed: every try was used"},"attempts":{"type":"integer"},"next_attempt_at":{"type":["string","null"],"format":"date-time"},"response_status":{"type":["integer","null"]},"error":{"type":["string","null"]},"response_body":{"type":["string","null"],"description":"The start of the receiver's answer"},"attempt_log":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","format":"date-time"},"status":{"type":["integer","null"]},"error":{"type":["string","null"]},"ms":{"type":["integer","null"]}},"required":["at","status","error","ms"]}},"created_at":{"type":"string","format":"date-time"},"delivered_at":{"type":["string","null"],"format":"date-time"}},"required":["id","event_id","event_type","status","attempts","next_attempt_at","response_status","error","response_body","attempt_log","created_at","delivered_at"]},"WebhookDeliveryList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}}},"required":["data"]},"WebhookDeleted":{"type":"object","properties":{"deleted":{"type":"boolean"}},"required":["deleted"]},"WebhookEvent":{"type":"object","properties":{"id":{"type":"string","description":"evt_..., stable across retries"},"type":{"type":"string","description":"For example webhook.test"},"api_version":{"type":"string","enum":["v1"]},"created_at":{"type":"string","format":"date-time"},"workspace_key":{"type":"string"},"data":{"type":"object","additionalProperties":true}},"required":["id","type","api_version","created_at","workspace_key","data"]},"AccessRequest":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["download","view"]},"name":{"type":"string"},"company":{"type":["string","null"]},"email":{"type":"string"},"message":{"type":["string","null"]},"status":{"type":"string","enum":["pending","approved","rejected"]},"created_at":{"type":"string","format":"date-time"},"decided_at":{"oneOf":[{"type":"null"},{"type":"string","format":"date-time"}]}},"required":["id","kind","name","company","email","message","status","created_at","decided_at"]},"RequestList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AccessRequest"}},"next_cursor":{"type":["string","null"],"description":"Pass as ?cursor= for the next page; null on the last page. Opaque: do not build or parse it."}},"required":["data","next_cursor"]},"Decision":{"type":"object","properties":{"action":{"type":"string","enum":["approve","reject"]}},"required":["action"]},"DecisionResult":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["approved","rejected"]},"emailed":{"type":"boolean"}},"required":["id","status"]},"Entry":{"type":"object","properties":{"id":{"type":"string","description":"A file id is digits, a folder id is a uuid"},"type":{"type":"string","enum":["file","folder"]},"name":{"type":"string"},"size":{"type":["integer","null"],"minimum":0,"description":"Bytes. null for a folder"},"category":{"type":["string","null"],"description":"The file type the app tags it with, for example image, video or document. null for a folder"},"parent_id":{"type":["string","null"],"description":"The id of the folder it sits in. null in the library root"},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"},"modified_at":{"type":["string","null"],"format":"date-time","description":"The file's own modification time when the uploader set one, else updated_at"},"sha256":{"type":["string","null"],"description":"SHA-256 of the bytes as lowercase hex, when known. null for a folder"},"sha256_source":{"type":["string","null"],"enum":["server","client",null],"description":"server: we verified it; client: the uploader's unverified claim"},"etag":{"type":["string","null"],"description":"A marker that changes when the file changes. null for a folder"},"protected":{"type":"boolean","description":"True when a protection rule applies to the item; protection_kind says which. Some writes on protected items are refused"},"protection_kind":{"type":["string","null"],"enum":["system","request","team","transfer",null]},"path":{"type":"string","description":"The absolute path. Present on single-item reads, on writes and in a recursive listing; absent from a plain folder listing"}},"required":["id","type","name","size","category","parent_id","created_at","updated_at","modified_at","sha256","sha256_source","etag","protected","protection_kind"]},"EntryWithPath":{"type":"object","properties":{"id":{"type":"string","description":"A file id is digits, a folder id is a uuid"},"type":{"type":"string","enum":["file","folder"]},"name":{"type":"string"},"size":{"type":["integer","null"],"minimum":0,"description":"Bytes. null for a folder"},"category":{"type":["string","null"],"description":"The file type the app tags it with, for example image, video or document. null for a folder"},"parent_id":{"type":["string","null"],"description":"The id of the folder it sits in. null in the library root"},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"},"modified_at":{"type":["string","null"],"format":"date-time","description":"The file's own modification time when the uploader set one, else updated_at"},"sha256":{"type":["string","null"],"description":"SHA-256 of the bytes as lowercase hex, when known. null for a folder"},"sha256_source":{"type":["string","null"],"enum":["server","client",null],"description":"server: we verified it; client: the uploader's unverified claim"},"etag":{"type":["string","null"],"description":"A marker that changes when the file changes. null for a folder"},"protected":{"type":"boolean","description":"True when a protection rule applies to the item; protection_kind says which. Some writes on protected items are refused"},"protection_kind":{"type":["string","null"],"enum":["system","request","team","transfer",null]},"path":{"type":"string","description":"The absolute path, such as /photos/2026/a.jpg"}},"required":["id","type","name","size","category","parent_id","created_at","updated_at","modified_at","sha256","sha256_source","etag","protected","protection_kind","path"]},"FileList":{"type":"object","properties":{"folder":{"type":"object","properties":{"id":{"type":["string","null"],"description":"The folder that was listed; null for the library root"}},"required":["id"]},"entries":{"type":"array","items":{"$ref":"#/components/schemas/Entry"}},"next_cursor":{"type":["string","null"],"description":"Pass as ?cursor= for the next page; null on the last page. Opaque: do not build or parse it."}},"required":["folder","entries","next_cursor"]},"FileDownload":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"size":{"type":"integer","minimum":0,"description":"Bytes"},"download_url":{"type":"string","format":"uri","description":"A signed URL; no token needed to fetch it"},"expires_in":{"type":"integer","description":"Seconds the URL keeps working (900)"},"links_expire":{"type":"boolean","description":"Always true: ask again for a fresh link"}},"required":["id","name","size","download_url","expires_in","links_expire"]},"FolderCreate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"The folder name, at most 255 bytes"},"parent_id":{"type":["string","null"],"format":"uuid","description":"The folder to create it in. Omit or null for the library root"}},"required":["name"]},"FilePatch":{"type":"object","minProperties":1,"description":"Send at least one key. Other keys, such as a path or a parent name, are refused.","properties":{"name":{"type":"string","minLength":1,"description":"The new name, at most 255 bytes"},"parent_id":{"type":["string","null"],"format":"uuid","description":"Move into this folder; null moves to the library root"},"modified_at":{"type":"string","format":"date-time","description":"The file's own modification time: ISO 8601 with a time zone, after 1970-01-02 and at most one day ahead. Files only"}}},"FileCopy":{"type":"object","description":"Both keys are optional.","properties":{"parent_id":{"type":["string","null"],"format":"uuid","description":"The destination folder; null for the library root; omitted keeps the original's folder"},"name":{"type":"string","minLength":1,"description":"The new name, at most 255 bytes; omitted keeps the original's name"}}},"DeleteResult":{"type":"object","properties":{"deleted":{"type":"boolean","description":"Always true"},"deleted_transfers":{"type":"array","items":{"type":"integer"},"description":"The ids of the transfers deleted with the item (empty unless confirm_delete_transfers was true)"}},"required":["deleted","deleted_transfers"]},"Usage":{"type":"object","properties":{"storage":{"type":"object","properties":{"used_bytes":{"type":"integer","minimum":0},"limit_bytes":{"type":["integer","null"],"minimum":0,"description":"The plan's limit; null when there is none"},"free_bytes":{"type":["integer","null"],"minimum":0,"description":"limit_bytes minus used_bytes; null when there is no limit"}},"required":["used_bytes","limit_bytes","free_bytes"]}},"required":["storage"]},"WorkspaceRef":{"type":"object","properties":{"workspace_key":{"type":["string","null"],"description":"Send as X-Workspace-Key"},"name":{"type":["string","null"]},"url":{"type":["string","null"]},"relationship":{"type":"string","enum":["owner","member","linked"]}},"required":["workspace_key","name","url","relationship"]},"WorkspaceList":{"type":"object","properties":{"workspaces":{"type":"array","items":{"$ref":"#/components/schemas/WorkspaceRef"}}},"required":["workspaces"]},"UploadStart":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"The file name, at most 255 bytes"},"size":{"type":"integer","minimum":0,"description":"The file's size in bytes. 0 creates an empty file at once"},"folder_id":{"type":["string","null"],"format":"uuid","description":"The folder to upload into. Omit or null for the library root"},"content_type":{"type":"string","maxLength":100,"description":"The media type, without control characters. Default application/octet-stream"},"sha256":{"type":"string","pattern":"^[0-9a-fA-F]{64}$","description":"The SHA-256 of the file's bytes as 64 hexadecimal characters"},"on_conflict":{"type":"string","enum":["version","separate","skip"],"description":"Your answer when the app's duplicate rule would ask: version, separate or skip. See startUpload"},"modified_at":{"type":"string","format":"date-time","description":"The file's own modification time: ISO 8601 with a time zone, after 1970-01-02 and at most one day ahead"}},"required":["name","size"]},"UploadPart":{"type":"object","properties":{"partNumber":{"type":"integer","minimum":1},"url":{"type":"string","format":"uri","description":"A signed URL: PUT that part's bytes to it"}},"required":["partNumber","url"]},"UploadStarted":{"type":"object","properties":{"action":{"type":"string","enum":["upload"]},"will_be_renamed":{"type":"boolean","description":"True when the name was taken and the file will get a numbered name"},"folder_id":{"type":["string","null"]},"id":{"type":"string","format":"uuid"},"status":{"type":"string","description":"pending, uploading, completed, failed, aborted or expired"},"name":{"type":"string"},"size":{"type":"integer","minimum":0},"mode":{"type":"string","enum":["single","multipart"],"description":"single: one signed URL; multipart: signed part URLs of part_size bytes each"},"part_size":{"type":"integer","minimum":1,"description":"Bytes per part (the last part can be smaller)"},"part_count":{"type":"integer","minimum":1},"expires_at":{"type":"string","format":"date-time"},"content_type":{"type":"string"},"uploads":{"type":"array","items":{"$ref":"#/components/schemas/UploadPart"},"description":"Signed URLs: one for a single upload, the first batch of parts for a multipart upload"}},"required":["action","will_be_renamed","folder_id","id","status","name","size","mode","part_size","part_count","expires_at","content_type","uploads"]},"UploadStartedVersion":{"type":"object","properties":{"action":{"type":"string","enum":["upload"]},"kind":{"type":"string","enum":["version"],"description":"This upload adds a new version to an existing file"},"will_be_renamed":{"type":"boolean","description":"Always false for a version"},"id":{"type":"string","format":"uuid"},"status":{"type":"string","description":"pending"},"name":{"type":"string"},"size":{"type":"integer","minimum":0},"file_id":{"type":"string","description":"The existing file this version belongs to"},"folder_id":{"type":["string","null"]},"retention_days":{"type":["integer","null"],"description":"How long older versions are kept; null when there is no limit"},"mode":{"type":"string","enum":["single","multipart"],"description":"single: one signed URL; multipart: signed part URLs of part_size bytes each"},"part_size":{"type":"integer","minimum":1},"part_count":{"type":"integer","minimum":1},"multipart_id":{"type":"string","description":"Multipart uploads only: send it back where an endpoint asks for multipart_id"},"uploads":{"type":"array","items":{"$ref":"#/components/schemas/UploadPart"},"description":"Signed URLs: one for a single upload, the first batch of parts for a multipart upload"}},"required":["action","kind","will_be_renamed","id","status","name","size","file_id","folder_id","retention_days","mode","part_size","part_count","uploads"]},"FileCreated":{"type":"object","properties":{"action":{"type":"string","enum":["created"]},"kind":{"type":"string","enum":["empty"]},"file":{"oneOf":[{"$ref":"#/components/schemas/EntryWithPath"},{"type":"null"}],"description":"The empty file that was created"}},"required":["action","kind","file"]},"UploadSkipped":{"type":"object","properties":{"action":{"type":"string","enum":["skip"]},"existing":{"oneOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]},{"type":"null"}],"description":"The identical file that is already there"}},"required":["action","existing"]},"UploadStatus":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","description":"pending, uploading, completed, failed, aborted or expired"},"name":{"type":"string"},"size":{"type":"integer","minimum":0},"mode":{"type":"string","enum":["single","multipart"],"description":"single: one signed URL; multipart: signed part URLs of part_size bytes each"},"part_size":{"type":"integer","minimum":1},"part_count":{"type":"integer","minimum":1},"expires_at":{"type":"string","format":"date-time"},"parts_received":{"type":"integer","minimum":0,"description":"Multipart uploads: how many parts have arrived"},"file":{"oneOf":[{"$ref":"#/components/schemas/EntryWithPath"},{"type":"null"}],"description":"The finished file, once the upload is completed"}},"required":["id","status","name","size","mode","part_size","part_count","expires_at"]},"UploadStatusVersion":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["version"]},"status":{"type":"string","enum":["completed","pending","expired"]},"size":{"type":"integer","minimum":0},"file_id":{"type":"string"},"mode":{"type":"string","enum":["single","multipart"],"description":"single: one signed URL; multipart: signed part URLs of part_size bytes each"},"part_size":{"type":"integer","minimum":1},"part_count":{"type":"integer","minimum":1},"parts_received":{"type":"integer","minimum":0,"description":"Multipart uploads: how many parts have arrived"}},"required":["id","kind","status","size","file_id","mode","part_size","part_count"]},"UploadAborted":{"type":"object","properties":{"aborted":{"type":"boolean","description":"Always true"}},"required":["aborted"]},"UploadPartsRequest":{"type":"object","description":"All keys are optional.","properties":{"from_part":{"type":"integer","minimum":1,"default":1,"description":"The first part number to sign; at most part_count"},"count":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"How many parts to sign"},"multipart_id":{"type":"string","maxLength":1023,"description":"For a multipart version upload: the multipart_id that startUpload returned"}}},"UploadParts":{"type":"object","properties":{"uploads":{"type":"array","items":{"$ref":"#/components/schemas/UploadPart"}}},"required":["uploads"]},"UploadCompleteRequest":{"type":"object","description":"All keys are optional; an empty body is fine.","properties":{"multipart_id":{"type":"string","maxLength":1023,"description":"For a multipart version upload: the multipart_id that startUpload returned"},"sha256":{"type":"string","pattern":"^[0-9a-fA-F]{64}$","description":"The SHA-256 of the file's bytes as 64 hexadecimal characters"},"modified_at":{"type":"string","format":"date-time","description":"The file's own modification time: ISO 8601 with a time zone, after 1970-01-02 and at most one day ahead"}}},"UploadCompleted":{"type":"object","properties":{"id":{"type":"string","description":"A file id is digits, a folder id is a uuid"},"type":{"type":"string","enum":["file","folder"]},"name":{"type":"string"},"size":{"type":["integer","null"],"minimum":0,"description":"Bytes. null for a folder"},"category":{"type":["string","null"],"description":"The file type the app tags it with, for example image, video or document. null for a folder"},"parent_id":{"type":["string","null"],"description":"The id of the folder it sits in. null in the library root"},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"},"modified_at":{"type":["string","null"],"format":"date-time","description":"The file's own modification time when the uploader set one, else updated_at"},"sha256":{"type":["string","null"],"description":"SHA-256 of the bytes as lowercase hex, when known. null for a folder"},"sha256_source":{"type":["string","null"],"enum":["server","client",null],"description":"server: we verified it; client: the uploader's unverified claim"},"etag":{"type":["string","null"],"description":"A marker that changes when the file changes. null for a folder"},"protected":{"type":"boolean","description":"True when a protection rule applies to the item; protection_kind says which. Some writes on protected items are refused"},"protection_kind":{"type":["string","null"],"enum":["system","request","team","transfer",null]},"path":{"type":"string","description":"The absolute path, such as /photos/2026/a.jpg"},"version_created":{"type":"boolean","description":"Version uploads only: false when the bytes were identical to the current version, so nothing was added"}},"required":["id","type","name","size","category","parent_id","created_at","updated_at","modified_at","sha256","sha256_source","etag","protected","protection_kind","path"]}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"Makes a write safe to repeat. Send a random value (a UUID is fine) of up to 255 visible characters. A repeat of the same request gets the first answer again, with the header `Idempotent-Replayed: true`, and does nothing twice. The same key for a different request is 422 `idempotency_key_reused`; the same request while the first one is still running is 409 `idempotency_in_progress`. A 5xx or 429 is not remembered, so retrying it runs the request again. Keys last 24 hours and belong to the account that created the token.","schema":{"type":"string","minLength":1,"maxLength":255}}},"headers":{"RateLimitLimit":{"description":"Requests allowed per minute in this token's bucket","schema":{"type":"integer"}},"RateLimitRemaining":{"description":"Requests left in the current minute","schema":{"type":"integer"}},"RateLimitReset":{"description":"When the current window ends, in Unix seconds","schema":{"type":"integer"}},"RetryAfter":{"description":"Seconds to wait before trying again","schema":{"type":"integer"}},"ApiVersion":{"description":"The API version that answered","schema":{"type":"string"}},"WwwAuthenticate":{"description":"Bearer, on every 401","schema":{"type":"string"}}},"responses":{"BadRequest":{"description":"The request is invalid: a parameter, the body or the workspace key is wrong (invalid_request, invalid_name, workspace_required, confirmation_required and others). code says which","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"Unauthorized":{"description":"The token is missing, invalid or revoked (unauthorized), or it is an older workspace-bound token (legacy_token). Create a token in Settings > API","headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WwwAuthenticate"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"Forbidden":{"description":"The token lacks the scope this operation needs (see x-required-scope) or has no scopes (token_without_scopes), has no access to the workspace (no_access), its creator may not do this (forbidden), or the item is protected (protected)","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"NotFound":{"description":"The brand, request, file, folder or upload does not exist in this workspace (not_found)","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"Conflict":{"description":"The request conflicts with the current state, for example a taken name (name_taken), a request that is already decided, an item a transfer holds (transfer_active), or missing upload parts (incomplete); or, on a write, a request with the same Idempotency-Key is still running (idempotency_in_progress). code says which","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"Gone":{"description":"Gone for good: the upload expired or failed (expired, failed), or the bin's retention has passed (expired)","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"PayloadTooLarge":{"description":"Over the plan's storage or file-size limit, or too large to list (storage_full, file_too_large, storage_limit_exceeded, too_large)","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"Unprocessable":{"description":"The bytes do not match what was announced (integrity_mismatch, size_mismatch), or the Idempotency-Key was already used for a different request (idempotency_key_reused)","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"RateLimited":{"description":"Too many requests (rate_limited): wait Retry-After seconds. Too many unfinished uploads is too_many_uploads","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"ServerError":{"description":"Something went wrong on our side (server_error). Try again later","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"BadGateway":{"description":"Cloud storage did not answer (storage_unavailable). Try again","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"Unavailable":{"description":"Temporarily unavailable: the files API is switched off, the plan or storage could not be read, or an Idempotency-Key could not be recorded so the write was not run (unavailable, entitlement_unresolved). Try again later","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","bearerFormat":"tk_ token","description":"Scopes: brands:read (Read brands, their assets, brand.md and analytics); brands:write (Update a brand's text, links, access and settings); brands:create (Create brands, delete them to the bin and restore them from it); brands:requests (List download and view requests and approve or reject them); webhooks:manage (Add, change and remove webhook endpoints, send test events and read the delivery log); files:read (List and download files and folders); files:write (Create folders, rename and delete files and folders (and restore them from the bin); uploads are separate endpoints). Create a token in Settings > API."}}},"x-error-codes":{"invalid_request":{"status":400,"title":"Invalid request","meaning":"A field is missing, has the wrong type or is out of range."},"invalid_workspace":{"status":400,"title":"Invalid workspace key","meaning":"The workspace value is malformed. A key is eight lowercase letters and digits (GET /workspaces lists them)."},"workspace_required":{"status":400,"title":"Workspace key required","meaning":"No workspace key was sent. Send X-Workspace-Key (or workspace_key) on every call that works inside a workspace."},"workspace_key_required":{"status":400,"title":"Workspace id not accepted","meaning":"A workspace id was sent where the eight-character workspace key is required."},"conflicting_workspace":{"status":400,"title":"Conflicting workspace","meaning":"The workspace is named twice with different values, for example in the header and in the query."},"not_supported":{"status":400,"title":"Not supported","meaning":"The operation does not apply to this item, for example a modification time on a folder."},"invalid_name":{"status":400,"title":"Invalid name","meaning":"The name is empty, is . or .., contains / or control characters, or is not valid Unicode."},"name_too_long":{"status":400,"title":"Name too long","meaning":"The name is longer than 255 bytes in UTF-8."},"invalid_destination":{"status":400,"title":"Invalid destination","meaning":"A folder cannot be moved into itself or one of its own subfolders."},"version_too_large":{"status":400,"title":"Version too large","meaning":"The file is too large to save as a new version."},"confirmation_required":{"status":400,"title":"Confirmation required","meaning":"A destructive or publishing step needs its confirmation: confirm_public: true to make a brand public, confirm_delete: true to delete a brand."},"unauthorized":{"status":401,"title":"Unauthorized","meaning":"The token is missing, malformed, invalid or revoked."},"legacy_token":{"status":401,"title":"Retired token","meaning":"The token is an older workspace token and no longer works. Create a new token in Settings > API."},"forbidden":{"status":403,"title":"Forbidden","meaning":"The token lacks the scope this operation needs, or its creator's role in the workspace is not enough."},"token_without_scopes":{"status":403,"title":"Token has no scopes","meaning":"The token was created before scopes existed. Create a new token and choose its scopes."},"no_access":{"status":403,"title":"No access to this workspace","meaning":"The workspace key is unknown, or the person who created the token cannot access that workspace. Both answer the same, so keys cannot be probed."},"workspace_suspended":{"status":403,"title":"Workspace suspended","meaning":"The workspace is suspended, so its API is closed as well. Contact support or the workspace owner."},"protected":{"status":403,"title":"Protected item","meaning":"The item is protected (system, request, team or transfer folders) and cannot be changed through the API. details.kind says why."},"not_found":{"status":404,"title":"Not found","meaning":"The item, upload or brand does not exist in this workspace."},"conflict":{"status":409,"title":"Conflict","meaning":"The request clashes with the current state, for example a file with the same name exists. details lists the choices."},"name_taken":{"status":409,"title":"Name already taken","meaning":"A sibling with this name already exists in the folder."},"ambiguous_path":{"status":409,"title":"Ambiguous path","meaning":"Two folders on the path share a name, so the path points at more than one item. Use ids."},"transfer_active":{"status":409,"title":"Active transfer","meaning":"The item is part of an active transfer. details.confirm_with names the field that confirms deleting those transfers."},"incomplete":{"status":409,"title":"Upload incomplete","meaning":"Not every part has arrived. details.missing_parts lists the parts still to send."},"empty_version_not_supported":{"status":409,"title":"Empty version not supported","meaning":"An empty file cannot be saved as a new version. details.choices lists what to send instead."},"size_unreadable":{"status":409,"title":"Size unreadable","meaning":"The source file's size could not be read."},"parent_unavailable":{"status":409,"title":"Parent folder unavailable","meaning":"The folder the item was in is in the bin or gone. Restore that folder first."},"not_multipart":{"status":409,"title":"Not a multipart upload","meaning":"The upload is a single PUT and has no parts to sign."},"not_deleted":{"status":409,"title":"Not in the bin","meaning":"Only an item in the bin can be restored."},"not_an_api_upload":{"status":409,"title":"Not an API upload","meaning":"The upload was not started through the API."},"folder_unresolved":{"status":409,"title":"Folder unresolved","meaning":"The folder of the file could not be located."},"finalizing":{"status":409,"title":"Upload is finalizing","meaning":"The upload is already being completed. Retry shortly."},"expired":{"status":410,"title":"Expired","meaning":"The upload session or the bin retention window has passed."},"upload_expired":{"status":410,"title":"Upload expired","meaning":"The upload is finished or expired. Start it again."},"failed":{"status":410,"title":"Upload failed","meaning":"The upload failed. Start it again."},"file_too_large":{"status":413,"title":"File too large","meaning":"The file is larger than the plan allows."},"storage_full":{"status":413,"title":"Storage full","meaning":"There is not enough storage left. details.limit may carry the plan's limit in bytes."},"too_large":{"status":413,"title":"Too large","meaning":"A recursive listing covers more folders than one call can return. List a smaller folder."},"integrity_mismatch":{"status":422,"title":"Integrity check failed","meaning":"The stored file's SHA-256 differs from the one sent. details.expected and details.stored may carry both hashes."},"size_mismatch":{"status":422,"title":"Size mismatch","meaning":"The stored size differs from the size announced when the upload started."},"idempotency_in_progress":{"status":409,"title":"Request still running","meaning":"A request with the same Idempotency-Key has not finished. Wait Retry-After seconds and send it again; you get its answer."},"idempotency_key_reused":{"status":422,"title":"Idempotency key reused","meaning":"The Idempotency-Key was already used for a different request (another path, query, workspace or body). Use a new key."},"rate_limited":{"status":429,"title":"Rate limit exceeded","meaning":"Too many requests in this minute. Wait Retry-After seconds."},"too_many_uploads":{"status":429,"title":"Too many uploads","meaning":"Too many uploads are open at once. Finish or abort some first."},"file_not_found":{"status":404,"title":"File not found","meaning":"The file the new version belongs to does not exist any more."},"upload_not_found":{"status":404,"title":"Upload not found","meaning":"The version upload does not exist or was cleaned up. Start it again."},"version_unavailable":{"status":404,"title":"Version unavailable","meaning":"The version this upload was based on is no longer available."},"file_in_transfer":{"status":409,"title":"File is in a transfer","meaning":"A transfer uses this file. Confirm the transfer update in the app, or switch on automatic transfer updates in the workspace's file settings."},"upload_in_progress":{"status":409,"title":"Version upload in progress","meaning":"Someone else is already uploading a new version of this file. Retry shortly."},"current_version_changed":{"status":409,"title":"File changed meanwhile","meaning":"The file got another version while this upload was running. Upload again."},"storage_usage_unreadable":{"status":409,"title":"Storage usage unreadable","meaning":"Storage usage could not be verified, so nothing was saved. Retry."},"storage_limit_exceeded":{"status":413,"title":"Storage limit exceeded","meaning":"There is not enough storage for this version. Older versions count toward storage until they expire."},"version_failed":{"status":500,"title":"Version could not be saved","meaning":"The new version could not be saved. Retry; if it persists, contact support."},"server_error":{"status":500,"title":"Server error","meaning":"Something went wrong on our side. Retry; if it persists, contact support."},"storage_unavailable":{"status":502,"title":"Storage unavailable","meaning":"The storage backend failed. Nothing was created; retry."},"unavailable":{"status":503,"title":"Service unavailable","meaning":"The endpoint is switched off or the plan could not be confirmed. Retry later."},"entitlement_unresolved":{"status":503,"title":"Plan could not be resolved","meaning":"The plan could not be confirmed. Retry."}},"paths":{"/brands":{"get":{"operationId":"listBrands","summary":"List brands","description":"Lists the brand pages of the workspace as short summaries; use getBrand for one in full. Page with limit and next_cursor. Needs the brands:read scope, and the token's creator must be an owner or admin of the workspace.","tags":["Brands"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"limit","in":"query","description":"1 to 100, default 25","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"cursor","in":"query","description":"next_cursor from the previous page. Opaque: do not build or parse it","schema":{"type":"string"}}],"security":[{"bearer":["brands:read"]}],"x-required-scope":"brands:read","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createBrand","summary":"Create a brand","description":"Adds a brand page. name is required; the slug defaults to the name (lower case letters, digits and dashes). The plan's brand page limit applies exactly as in the app: at the limit the call is refused with 403 forbidden (details.entitlement names the limit), and a slug already used in the workspace is 409 name_taken. A new brand is always a private draft and not public; open it later with updateBrand (which has its own confirmation for going public). Needs brands:create.","tags":["Brands"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandCreate"}}}},"security":[{"bearer":["brands:create"]}],"x-required-scope":"brands:create","responses":{"201":{"description":"The new brand (a private draft)","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Brand"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/brands/{brand}":{"get":{"operationId":"getBrand","summary":"Get a brand","description":"Returns one brand in full: text, social links, colors, fonts, access mode, tracking ids, SEO fields, team, press and its public URLs. Address it by id (uuid) or slug. Needs brands:read.","tags":["Brands"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"brand","in":"path","required":true,"description":"Brand id (uuid) or slug","schema":{"type":"string"}}],"security":[{"bearer":["brands:read"]}],"x-required-scope":"brands:read","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Brand"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteBrand","summary":"Delete a brand (to the bin)","description":"Moves the brand to the bin, where it can be restored with restoreDeletedBrand. How long it can be restored follows the plan's recovery-bin retention, the same as files: 30 days on Free, 90 on Pro and Agency. The page goes offline, its slug and its place under the plan's brand limit are freed, and its domains are detached from hosting and are not restored. Access requests, analytics and the kit link are not kept. Needs confirm_delete: true (query or body), otherwise 400 confirmation_required. Needs brands:create.","tags":["Brands"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"brand","in":"path","required":true,"description":"Brand id (uuid) or slug","schema":{"type":"string"}},{"name":"confirm_delete","in":"query","description":"Must be true; the body field of the same name works too","schema":{"type":"boolean"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"security":[{"bearer":["brands:create"]}],"x-required-scope":"brands:create","responses":{"200":{"description":"The brand is in the bin","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedBrand"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}},"patch":{"operationId":"updateBrand","summary":"Update a brand","description":"Changes the brand fields you send and leaves the rest alone. Send at least one field; unknown fields are refused. The slug, files, passwords and domains cannot be changed here. Setting access to public on a brand that is not public yet needs confirm_public: true, otherwise the call is refused with 400 confirmation_required. Returns the whole brand after the change. Needs brands:write.","tags":["Brands"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"brand","in":"path","required":true,"description":"Brand id (uuid) or slug","schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandPatch"}}}},"security":[{"bearer":["brands:write"]}],"x-required-scope":"brands:write","responses":{"200":{"description":"The brand after the change","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Brand"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/deleted-brands":{"get":{"operationId":"listDeletedBrands","summary":"List deleted brands that can be restored","description":"Lists the brands in the bin, newest deletion first, each with restorable_until, the last moment it can come back under the plan's retention (null if the plan could not be read). Brands past their retention are not listed. Needs brands:create.","tags":["Brands"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}}],"security":[{"bearer":["brands:create"]}],"x-required-scope":"brands:create","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedBrandList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/deleted-brands/{brand}/restore":{"post":{"operationId":"restoreDeletedBrand","summary":"Restore a deleted brand","description":"Puts a binned brand back with the same id and content. The plan's brand page limit applies as in the app (403 forbidden). Past the plan's retention it is 410 expired. If its slug is used now, send another slug in the body, otherwise 409 name_taken. Domains are not restored; connect them again. Needs brands:create.","tags":["Brands"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"brand","in":"path","required":true,"description":"The id (uuid) of the deleted brand from listDeletedBrands","schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandRestore"}}}},"security":[{"bearer":["brands:create"]}],"x-required-scope":"brands:create","responses":{"200":{"description":"The restored brand","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Brand"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"410":{"$ref":"#/components/responses/Gone"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/brands/{brand}/assets":{"get":{"operationId":"listBrandAssets","summary":"List a brand's files with short-lived download links","description":"Lists the brand's icon, main logo and banner, its logos and its file collections, each file with a short-lived download link. The links expire (links_expire is always true), so list again when you need fresh ones. Needs brands:read.","tags":["Brands"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"brand","in":"path","required":true,"description":"Brand id (uuid) or slug","schema":{"type":"string"}}],"security":[{"bearer":["brands:read"]}],"x-required-scope":"brands:read","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandAssets"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/brands/{brand}/markdown":{"get":{"operationId":"getBrandMarkdown","summary":"The brand as markdown (brand.md)","description":"Returns the brand as one markdown document (brand.md), the form AI assistants read best. The response is text/markdown, not JSON. Needs brands:read.","tags":["Brands"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"brand","in":"path","required":true,"description":"Brand id (uuid) or slug","schema":{"type":"string"}}],"security":[{"bearer":["brands:read"]}],"x-required-scope":"brands:read","responses":{"200":{"description":"The brand as markdown","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"text/markdown":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/brands/{brand}/analytics":{"get":{"operationId":"getBrandAnalytics","summary":"Page views, downloads and requests","description":"Returns page views, downloads and requests for the brand as totals and daily series. period is 30d (default), 90d or all. Needs brands:read.","tags":["Brands"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"brand","in":"path","required":true,"description":"Brand id (uuid) or slug","schema":{"type":"string"}},{"name":"period","in":"query","description":"30d (default), 90d or all","schema":{"type":"string","enum":["30d","90d","all"],"default":"30d"}}],"security":[{"bearer":["brands:read"]}],"x-required-scope":"brands:read","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandAnalytics"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/brands/{brand}/requests":{"get":{"operationId":"listBrandRequests","summary":"List download and view requests","description":"Lists the download and view requests people sent from the brand page. Filter with status (pending, approved or rejected) and page with next_cursor. Needs brands:requests.","tags":["Requests"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"brand","in":"path","required":true,"description":"Brand id (uuid) or slug","schema":{"type":"string"}},{"name":"limit","in":"query","description":"1 to 100, default 25","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"cursor","in":"query","description":"next_cursor from the previous page. Opaque: do not build or parse it","schema":{"type":"string"}},{"name":"status","in":"query","description":"pending, approved or rejected","schema":{"type":"string","enum":["pending","approved","rejected"]}}],"security":[{"bearer":["brands:requests"]}],"x-required-scope":"brands:requests","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/files":{"get":{"operationId":"listFiles","summary":"List the files and folders inside a folder of the library (folders first, then files; the root by default)","description":"Lists what is inside one folder: folders first, then files, each in id order so a cursor never skips or repeats an entry. The library root is the default; pick another folder with folder (a folder id) or path (for example /photos/2026), not both. With recursive=true and a type, every descendant comes back as one flat list with absolute paths (a subtree above 5,000 folders is refused with 413 too_large). Page with limit and next_cursor. Needs files:read.","tags":["Files"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"folder","in":"query","description":"A folder id (uuid); omit for the root. Not together with path","schema":{"type":"string","format":"uuid"}},{"name":"path","in":"query","description":"A path of folder names such as /photos/2026. Not together with folder","schema":{"type":"string"}},{"name":"recursive","in":"query","description":"true to list EVERY descendant as one flat list with absolute paths (needs type); a subtree above 5,000 folders is refused","schema":{"type":"boolean"}},{"name":"type","in":"query","description":"file or folder; required with recursive=true","schema":{"type":"string","enum":["file","folder"]}},{"name":"limit","in":"query","description":"1 to 1000, default 100","schema":{"type":"integer","minimum":1,"maximum":1000,"default":100}},{"name":"cursor","in":"query","description":"next_cursor from the previous page. Opaque: do not build or parse it","schema":{"type":"string"}}],"security":[{"bearer":["files:read"]}],"x-required-scope":"files:read","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/files/{id}":{"get":{"operationId":"getFile","summary":"Get one file or folder, with its path and whether it is protected","description":"Returns one file or folder by id, with its absolute path and whether a protection rule applies to it (protected, protection_kind). A file id is digits, a folder id is a uuid. Needs files:read.","tags":["Files"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"id","in":"path","required":true,"description":"A file id (digits) or a folder id (uuid)","schema":{"type":"string"}}],"security":[{"bearer":["files:read"]}],"x-required-scope":"files:read","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntryWithPath"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}},"patch":{"operationId":"updateFile","summary":"Rename and/or move a file or folder, and/or set a file's own modification time (body: name, parent_id: a folder id or null for the root, modified_at)","description":"Renames and/or moves a file or folder, and/or sets a file's own modification time (modified_at, files only). Send at least one of name, parent_id (a folder id, or null for the library root) and modified_at; other keys such as a path or a parent name are refused. A name already used in the destination is 409 name_taken. Protected items (system, request or team folders, or an item a paid transfer holds) are 403 protected. Returns the item after the change. Needs files:write.","tags":["Files"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"id","in":"path","required":true,"description":"A file id (digits) or a folder id (uuid)","schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FilePatch"}}}},"security":[{"bearer":["files:write"]}],"x-required-scope":"files:write","responses":{"200":{"description":"The item after the change","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntryWithPath"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}},"delete":{"operationId":"deleteFile","summary":"Move a file or folder to the bin; if a transfer holds it, 409 transfer_active until confirm_delete_transfers=true","description":"Moves a file or folder to the bin, where the app's retention rule applies and restoreFile can bring it back. If a transfer holds the item the answer is 409 transfer_active and its details name the transfers; repeat with confirm_delete_transfers=true to delete those transfers as well. Protected items are 403 protected. Returns deleted: true and the ids of any transfers deleted with it. Needs files:write.","tags":["Files"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"id","in":"path","required":true,"description":"A file id (digits) or a folder id (uuid)","schema":{"type":"string"}},{"name":"confirm_delete_transfers","in":"query","description":"true to also delete the transfers that hold the item (only the exact text true counts)","schema":{"type":"boolean"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"security":[{"bearer":["files:write"]}],"x-required-scope":"files:write","responses":{"200":{"description":"Moved to the bin","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/files/{id}/download":{"get":{"operationId":"getFileDownloadLink","summary":"A short-lived download link for a file","description":"Returns a signed URL for a file's bytes. The URL works without the token for 15 minutes (expires_in is in seconds): fetch it at once, or ask again for a fresh one. Folders have no download link (400). Needs files:read.","tags":["Files"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"id","in":"path","required":true,"description":"A file id (digits) or a folder id (uuid)","schema":{"type":"string"}}],"security":[{"bearer":["files:read"]}],"x-required-scope":"files:read","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileDownload"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/folders":{"post":{"operationId":"createFolder","summary":"Create a folder (body: name, parent_id optional; a taken name is a 409)","description":"Creates a folder in the library root or inside parent_id. A name already used in that folder is 409 name_taken. Returns the new folder with 201. Needs files:write.","tags":["Files"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderCreate"}}}},"security":[{"bearer":["files:write"]}],"x-required-scope":"files:write","responses":{"201":{"description":"The new folder","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntryWithPath"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/workspaces":{"get":{"operationId":"listWorkspaces","summary":"The workspaces this token can be used for, with the workspace_key to send as X-Workspace-Key (needs any API access)","description":"Lists the workspaces this token can act on, with the workspace_key to send in X-Workspace-Key on every other call. Start here: it needs only a valid token that has at least one scope (any scope works) and no workspace key. relationship says how the token's creator is connected to each workspace (owner, member or linked).","tags":["Files"],"parameters":[],"security":[{"bearer":["files:read"]}],"x-required-scope":"files:read","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/files/by-path":{"get":{"operationId":"getFileByPath","summary":"One file or folder by its path, without listing the folder around it (404 not found, 409 ambiguous_path)","description":"Returns one file or folder by its path, for example /photos/2026/a.jpg, without listing the folder around it. 404 not_found when nothing is there; 409 ambiguous_path when more than one item has that path. Needs files:read.","tags":["Files"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"path","in":"query","required":true,"description":"A path such as /photos/2026/a.jpg","schema":{"type":"string"}}],"security":[{"bearer":["files:read"]}],"x-required-scope":"files:read","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntryWithPath"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/files/{id}/restore":{"post":{"operationId":"restoreFile","summary":"Restore a file or folder from the bin (same retention rule as the app)","description":"Restores a file or folder from the bin, under the same retention rule as the app. 409 not_deleted when the item is not in the bin; 409 parent_unavailable when its folder is gone; 410 expired when the retention period has passed. Returns the restored item. Needs files:write.","tags":["Files"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"id","in":"path","required":true,"description":"A file id (digits) or a folder id (uuid)","schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"security":[{"bearer":["files:write"]}],"x-required-scope":"files:write","responses":{"200":{"description":"The restored item","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntryWithPath"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"410":{"$ref":"#/components/responses/Gone"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/files/{id}/copy":{"post":{"operationId":"copyFile","summary":"Copy a file inside storage (body: parent_id, name; a taken name is 409, plan limits apply)","description":"Copies a file inside storage, with no download or re-upload. parent_id is the destination folder (null for the library root; omitted keeps the original's folder) and name the new name (omitted keeps the original's). A copy never renames silently: a taken name is 409 name_taken. Plan limits apply (413 storage_full, 413 file_too_large). Folders cannot be copied (400 not_supported). Returns the copy with 201. Needs files:write.","tags":["Files"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"id","in":"path","required":true,"description":"A file id (digits) or a folder id (uuid)","schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileCopy"}}}},"security":[{"bearer":["files:write"]}],"x-required-scope":"files:write","responses":{"201":{"description":"The copy","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntryWithPath"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/usage":{"get":{"operationId":"getUsage","summary":"Storage in use and the plan's limit (null when there is none)","description":"Returns the storage the workspace uses and its plan's limit, in bytes. limit_bytes and free_bytes are null when the plan has no limit. Needs files:read.","tags":["Files"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}}],"security":[{"bearer":["files:read"]}],"x-required-scope":"files:read","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/uploads":{"post":{"operationId":"startUpload","summary":"Start an upload into a folder (body: name, size, folder_id, content_type, sha256, on_conflict); returns signed URLs, or creates an empty file directly when size is 0","description":"Starts an upload of size bytes into folder_id (the library root by default). A small file gets one signed URL; a larger file gets mode multipart, a part_size and the first 20 signed part URLs (signUploadParts returns more). PUT the bytes to each URL, then call completeUpload. A file of size 0 is created at once (action created). When the name already exists in the folder and the app's duplicate rule would ask, the call is 409 conflict and details.choices lists your answers: send one as on_conflict (version adds a new version of the existing file, separate keeps both under a numbered name, skip uploads nothing). In other cases the same rule as the app applies: depending on the plan the existing file gets a new version or the new file gets a numbered name, and an identical file is skipped (action skip, status 200). A version upload answers with kind version and the existing file_id; the rest of the flow is the same. Needs files:write.","tags":["Files"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadStart"}}}},"security":[{"bearer":["files:write"]}],"x-required-scope":"files:write","responses":{"200":{"description":"Nothing to upload: an identical file is already there (action skip)","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadSkipped"}}}},"201":{"description":"The upload started (action upload), or a file of size 0 was created (action created)","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/UploadStarted"},{"$ref":"#/components/schemas/UploadStartedVersion"},{"$ref":"#/components/schemas/FileCreated"}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/uploads/{id}":{"get":{"operationId":"getUpload","summary":"Where an upload stands (never finishes it)","description":"Returns where an upload you started stands: status, parts_received for a multipart upload and, once finished, the file. It only reads and never finishes the upload. For a multipart version upload pass the multipart_id that startUpload returned. Needs files:write.","tags":["Files"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"id","in":"path","required":true,"description":"An upload id (uuid)","schema":{"type":"string","format":"uuid"}},{"name":"multipart_id","in":"query","description":"For a multipart version upload: the multipart_id that startUpload returned","schema":{"type":"string","maxLength":1023}}],"security":[{"bearer":["files:write"]}],"x-required-scope":"files:write","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/UploadStatus"},{"$ref":"#/components/schemas/UploadStatusVersion"}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}},"delete":{"operationId":"abortUpload","summary":"Abort an unfinished upload","description":"Aborts an unfinished upload and discards the bytes sent so far. Returns aborted: true. For a multipart version upload pass the multipart_id that startUpload returned. Needs files:write.","tags":["Files"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"id","in":"path","required":true,"description":"An upload id (uuid)","schema":{"type":"string","format":"uuid"}},{"name":"multipart_id","in":"query","description":"For a multipart version upload: the multipart_id that startUpload returned","schema":{"type":"string","maxLength":1023}},{"$ref":"#/components/parameters/IdempotencyKey"}],"security":[{"bearer":["files:write"]}],"x-required-scope":"files:write","responses":{"200":{"description":"Aborted","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadAborted"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"410":{"$ref":"#/components/responses/Gone"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/uploads/{id}/parts":{"post":{"operationId":"signUploadParts","summary":"Fresh signed URLs for a range of parts (from_part, count up to 100)","description":"Returns fresh signed URLs for a range of parts of a multipart upload: from_part (default 1) and count (default 20, up to 100). Use it when the first URLs have expired or to sign the next batch. A single-part upload answers 409 not_multipart; an expired upload 410. Needs files:write.","tags":["Files"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"id","in":"path","required":true,"description":"An upload id (uuid)","schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadPartsRequest"}}}},"security":[{"bearer":["files:write"]}],"x-required-scope":"files:write","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadParts"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"410":{"$ref":"#/components/responses/Gone"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/uploads/{id}/complete":{"post":{"operationId":"completeUpload","summary":"Finish the upload into the folder chosen at the start; optional body: sha256, modified_at (multipart_id is stored by the server); returns the file","description":"Finishes the upload: puts the file in the folder chosen at the start and returns it. If bytes are missing the answer is 409 incomplete and nothing is lost: details.missing_parts lists the parts to send (at most 1000 are listed); send them and call again. Calling it again after success returns the same file. Optional sha256 (checked by the server up to 100 MiB, kept as the client's claim above that) and modified_at (the file's own modification time) are recorded on the file. For a version upload, version_created says whether a new version was made (false when the bytes equal the current version). Bytes that do not match the announced size or the sha256 are 422. Needs files:write.","tags":["Files"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"id","in":"path","required":true,"description":"An upload id (uuid)","schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadCompleteRequest"}}}},"security":[{"bearer":["files:write"]}],"x-required-scope":"files:write","responses":{"200":{"description":"The finished file","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadCompleted"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"410":{"$ref":"#/components/responses/Gone"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/brands/{brand}/requests/{request}":{"post":{"operationId":"decideBrandRequest","summary":"Approve or reject a request","description":"Approves or rejects a request. A request that is already decided is a 409 conflict. emailed in the result says whether the requester was notified by email. Needs brands:requests.","tags":["Requests"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"brand","in":"path","required":true,"description":"Brand id (uuid) or slug","schema":{"type":"string"}},{"name":"request","in":"path","required":true,"description":"Request id (uuid) from the requests list","schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Decision"}}}},"security":[{"bearer":["brands:requests"]}],"x-required-scope":"brands:requests","responses":{"200":{"description":"The decision","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecisionResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/webhooks":{"get":{"operationId":"listWebhookEndpoints","summary":"List webhook endpoints","description":"Lists the workspace's webhook endpoints: where events are sent, which events each asked for, whether it is on, and why it was switched off if it was. A signing secret is never in this list. Needs webhooks:manage, and the token's creator must be an owner or admin of the workspace.","tags":["Webhooks"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}}],"security":[{"bearer":["webhooks:manage"]}],"x-required-scope":"webhooks:manage","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createWebhookEndpoint","summary":"Add a webhook endpoint","description":"Adds an address that Tarkle sends signed events to. The address must be https and public. The signing secret is in this answer only; keep it. A workspace can have up to 20 endpoints. Needs webhooks:manage.","tags":["Webhooks"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointCreate"}}}},"security":[{"bearer":["webhooks:manage"]}],"x-required-scope":"webhooks:manage","responses":{"201":{"description":"The endpoint and its signing secret","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointCreated"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/webhooks/{id}":{"get":{"operationId":"getWebhookEndpoint","summary":"Get a webhook endpoint","description":"Returns one endpoint. Needs webhooks:manage.","tags":["Webhooks"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"id","in":"path","required":true,"description":"A webhook endpoint id (uuid) from listWebhookEndpoints","schema":{"type":"string","format":"uuid"}}],"security":[{"bearer":["webhooks:manage"]}],"x-required-scope":"webhooks:manage","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateWebhookEndpoint","summary":"Change a webhook endpoint","description":"Changes the address, the events, the description or whether the endpoint is on. Turning it on again clears its failure count. Needs webhooks:manage.","tags":["Webhooks"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"id","in":"path","required":true,"description":"A webhook endpoint id (uuid) from listWebhookEndpoints","schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointUpdate"}}}},"security":[{"bearer":["webhooks:manage"]}],"x-required-scope":"webhooks:manage","responses":{"200":{"description":"The endpoint after the change","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}},"delete":{"operationId":"deleteWebhookEndpoint","summary":"Delete a webhook endpoint","description":"Deletes the endpoint, its secret and its delivery log. Needs webhooks:manage.","tags":["Webhooks"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"id","in":"path","required":true,"description":"A webhook endpoint id (uuid) from listWebhookEndpoints","schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"security":[{"bearer":["webhooks:manage"]}],"x-required-scope":"webhooks:manage","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeleted"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/webhooks/{id}/rotate-secret":{"post":{"operationId":"rotateWebhookSecret","summary":"Rotate the signing secret","description":"Makes a new signing secret and returns it once. For the next 24 hours every delivery is signed with both the new and the old secret (two v1 values in the Tarkle-Signature header), so a receiver can switch without missing one. Needs webhooks:manage.","tags":["Webhooks"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"id","in":"path","required":true,"description":"A webhook endpoint id (uuid) from listWebhookEndpoints","schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"security":[{"bearer":["webhooks:manage"]}],"x-required-scope":"webhooks:manage","responses":{"200":{"description":"The new secret","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSecretRotated"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/webhooks/{id}/test":{"post":{"operationId":"sendWebhookTestEvent","summary":"Send a test event","description":"Sends one webhook.test event to the endpoint now and returns what happened. One try, no retries, and it does not change the endpoint's state, so you can test an endpoint that is switched off. Needs webhooks:manage.","tags":["Webhooks"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"id","in":"path","required":true,"description":"A webhook endpoint id (uuid) from listWebhookEndpoints","schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"security":[{"bearer":["webhooks:manage"]}],"x-required-scope":"webhooks:manage","responses":{"200":{"description":"What happened to the test event","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDelivery"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/webhooks/{id}/deliveries":{"get":{"operationId":"listWebhookDeliveries","summary":"List an endpoint's deliveries","description":"The latest deliveries of an endpoint, newest first, with the status and every attempt. Deliveries are kept for 7 days. limit is 1 to 100, default 25. Needs webhooks:manage.","tags":["Webhooks"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"id","in":"path","required":true,"description":"A webhook endpoint id (uuid) from listWebhookEndpoints","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"1 to 100, default 25","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"security":[{"bearer":["webhooks:manage"]}],"x-required-scope":"webhooks:manage","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/webhooks/{id}/deliveries/{delivery}/redeliver":{"post":{"operationId":"redeliverWebhookEvent","summary":"Send an event again","description":"Sends an earlier event again, now, as a fresh run of tries. The endpoint must be on (409 otherwise). Needs webhooks:manage.","tags":["Webhooks"],"parameters":[{"name":"X-Workspace-Key","in":"header","required":true,"description":"The 8-character key of the workspace this call acts on; GET /workspaces lists the keys a token can use. A workspace id is refused (400 workspace_key_required)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"workspace_key","in":"query","description":"The same key as the X-Workspace-Key header, for clients that cannot set headers. Send one of the two, or both with the same value (different values are 400 conflicting_workspace)","schema":{"type":"string","pattern":"^[a-z0-9]{8}$"}},{"name":"id","in":"path","required":true,"description":"A webhook endpoint id (uuid) from listWebhookEndpoints","schema":{"type":"string","format":"uuid"}},{"name":"delivery","in":"path","required":true,"description":"A delivery id (uuid) from listWebhookDeliveries","schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"security":[{"bearer":["webhooks:manage"]}],"x-required-scope":"webhooks:manage","responses":{"200":{"description":"What happened to the resent event","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Tarkle-Api-Version":{"$ref":"#/components/headers/ApiVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDelivery"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/Unavailable"}}}}}}