{"openapi":"3.1.0","info":{"title":"Blotout Platform API","version":"0.1.0","description":"HTTP API for programmatic access to Blotout platform teams and their resources.\n\nProtected operations accept a team API token or OAuth access token sent as `Authorization: Bearer <token>`. The health check and the OAuth metadata, token, and revocation operations do not require a bearer token. Call `GET /me` to confirm a credential works and to discover the `teamId` other operations need.\n\nOutside the OAuth group, errors use one JSON envelope: `error` is a machine-readable slug to switch on, `message` optionally carries a human-readable reason, and `details` optionally carries field-level validation errors. The OAuth endpoints use the standard OAuth shape instead — `error` with `error_description` — and the unauthenticated health check reports `{ status: \"error\" }`. Success payloads are documented per operation."},"tags":[{"name":"System","description":"Operational endpoints used to check whether the Blotout platform API and its dependencies are available."},{"name":"User","description":"The identity behind the presented access token: who is calling, which team the token is bound to, and what access it carries."},{"name":"Hosts","description":"Cloudflare account connections that a team uses to provision and operate domains."},{"name":"Sites","description":"The sites a team serves through Qinto: creating one, publishing its DNS, choosing where it is delivered from, deploying it, retrieving the snippet to install, and setting bot protection and automatic capture."},{"name":"Site analytics","description":"What a site’s apps did over a time range: event counts by status, event or install, error counts per install, and the errors themselves."},{"name":"Site apps","description":"Apps installed on a site: what runs there, each install’s state, extra installs, and the install, version, enable, and uninstall operations."},{"name":"App store","description":"The catalog of approved apps a team can browse: searching it by words or category, and reading one app’s listing and what its newest approved version may do."},{"name":"Bundle purchases","description":"The bundles a team bought: buying one from the app store or through a bundle link for the sites the team chooses, and listing what the team holds."},{"name":"Teams","description":"The team a bearer credential is bound to, and the starting point for every other operation."},{"name":"Team members","description":"Team roster and user identity endpoints for resolving the people who belong to a team."},{"name":"Billing","description":"What a team pays for the Blotout platform: this month’s core usage charges and projection, each site’s share, the next charge date, the payment terms and past invoices."},{"name":"Storage links","description":"Configurations that let several of a team’s sites share one site’s storage — the identity graph and app storage — chosen per child site, per resource."},{"name":"Developer apps","description":"Apps an organization builds for Qinto sites: registering them, managing their metadata, and deleting them. Versions are pushed with the Qinto CLI."},{"name":"Developer bundles","description":"Offers that sell several of an organization’s apps together: creating Drafts, editing them, and deleting them."},{"name":"OAuth","description":"The OAuth 2.1 authorization-server endpoints external apps use to obtain and manage `qoa_` access tokens on behalf of the users who authorize them."}],"servers":[{"url":"https://qinto-api.blotout.io","description":"This deployment of the Blotout platform API."}],"components":{"securitySchemes":{"QintoAccessToken":{"type":"http","scheme":"bearer","description":"Opaque API token, sent on every request as `Authorization: Bearer <token>`. Generate one from the Blotout platform’s Team → API tokens page. Each token is bound to one team and carries only its selected policies."}},"schemas":{"Team":{"type":"object","properties":{"teamId":{"type":"string","description":"Server-assigned unique id of the team. Every other operation addresses a team with it.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"name":{"type":["string","null"],"description":"Display name of the team, or null when it has never been named.","example":"Acme"},"createdAt":{"type":"string","format":"date-time","description":"When the team was created, as an ISO 8601 UTC timestamp.","example":"2026-06-18T00:00:00.000Z"},"scopes":{"type":"array","items":{"type":"string"},"description":"The access granted specifically in this team.","example":["team:write"]}},"required":["teamId","name","createdAt","scopes"],"description":"A team the authenticated credential may access."},"TeamMember":{"type":"object","properties":{"userId":{"type":"string","description":"Unique id of the member’s Qinto user account, stable across all teams the user belongs to.","example":"9c1f6e73-2b84-4d05-b1a7-58e02c94f6d1"},"email":{"type":"string","description":"Email address the member signs in with; unique per user.","example":"jane@example.com"},"firstName":{"type":["string","null"],"description":"First name from the member’s profile, or null while the profile is incomplete.","example":"Jane"},"lastName":{"type":["string","null"],"description":"Last name from the member’s profile, or null while the profile is incomplete.","example":"Doe"},"joinedAt":{"type":"string","format":"date-time","description":"When the user joined the team, as an ISO 8601 UTC timestamp.","example":"2026-05-02T09:30:00.000Z"}},"required":["userId","email","firstName","lastName","joinedAt"],"description":"A Qinto user’s membership in the team."},"Host":{"type":"object","properties":{"hostId":{"type":"string","description":"Server-assigned unique id of the host. Address the host with it in the get, update and delete operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"name":{"type":"string","description":"Display name of the host, as shown on the Blotout platform.","example":"Production"},"accountId":{"type":"string","description":"Id of the Cloudflare account this host manages. It is fixed when the host is created.","example":"023e105f4ecef8ad9ca31a8372d0c353"},"zoneDomain":{"type":["string","null"],"description":"Cloudflare zone this host serves customer traffic from. Custom hostnames are created on it, and customers point their CNAME records at `<subdomain>.customers.<zoneDomain>`. Null until a zone is chosen — set it with the zone operation.","example":"agency.example.com"},"wfp":{"type":"boolean","description":"Whether the account participates in Workers for Platforms — it hosts multiple customer workers behind the Qinto dispatcher (for example, an agency account).","example":false},"createdAt":{"type":"string","format":"date-time","description":"When the host was connected to the team, as an ISO 8601 UTC timestamp.","example":"2026-06-18T00:00:00.000Z"}},"required":["hostId","name","accountId","zoneDomain","wfp","createdAt"],"description":"A Cloudflare account connected to the team. The API token that authorizes it is write-only and never part of this shape."},"CreateHostRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"Display name for the host, shown wherever the Blotout platform lists it. Pick something the team recognizes, e.g. the environment it serves. At most 80 characters; must be unique within the team.","example":"Production"},"accountId":{"type":"string","minLength":1,"description":"Id of the Cloudflare account to manage. Copy it from the Cloudflare dashboard (Account Home → the account’s overview sidebar).","example":"023e105f4ecef8ad9ca31a8372d0c353"},"apiToken":{"type":"string","minLength":1,"description":"Cloudflare API token that authorizes managing the account. It is verified live against the Cloudflare API before anything is stored, and it is write-only: no read operation ever returns it.","example":"YQSn-xWAQiiEh9qM58wZNnyQS7FUdoqGIUAbrh7T"},"wfp":{"type":"boolean","description":"Enable Workers for Platforms for this account when it hosts multiple customer workers behind the Qinto dispatcher (for example, an agency managing several customers). A control token is generated and installed on the account’s dispatcher. Defaults to false.","example":true}},"required":["name","accountId","apiToken"],"description":"Connection details for the Cloudflare account to register as a host."},"UpdateHostRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"New display name for the host; replaces the current one. At most 80 characters; must be unique within the team.","example":"Production"},"apiToken":{"type":"string","description":"Replacement Cloudflare API token. Omit it (or send an empty string) to keep the currently stored token; a non-empty value is verified live against the Cloudflare API before it replaces the stored one.","example":"YQSn-xWAQiiEh9qM58wZNnyQS7FUdoqGIUAbrh7T"}},"required":["name"],"additionalProperties":false,"description":"Full replacement of the host’s editable fields; the API token alone is optional. No other properties are accepted — a host’s Cloudflare account is fixed when it is created."},"SetHostZoneRequest":{"type":"object","properties":{"zoneDomain":{"type":"string","minLength":1,"description":"Zone to serve customer traffic from. It must exist in the host’s Cloudflare account — send one of the names the `zoneRequired` list returned. It cannot be changed once a site references this host.","example":"agency.example.com"}},"required":["zoneDomain"],"description":"The Cloudflare zone this host serves its customers from."},"Site":{"type":"object","properties":{"domainId":{"type":"string","description":"Server-assigned unique id of the site. Address the site with it in every other operation.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"name":{"type":["string","null"],"description":"Display name of the site, as shown on the Blotout platform.","example":"Storefront"},"domain":{"type":"string","description":"Hostname Qinto serves this site on, built from its subdomain and root domain. It is fixed at creation.","example":"shop.example.com"},"rootDomain":{"type":"string","description":"Customer domain the site belongs to.","example":"example.com"},"subdomain":{"type":"string","description":"Label Qinto serves the site from, under the root domain.","example":"shop"},"status":{"type":"string","enum":["pending","active"],"description":"`pending` until the site is first deployed, then `active`. Deleted sites are not returned at all.","example":"pending"},"jurisdiction":{"type":["string","null"],"enum":["eu","us",null],"description":"Jurisdiction the site’s data is held in, or null when unrestricted. Guaranteed for Durable Objects and object storage; other storage follows `locationHint` where it is supported, and is otherwise placed automatically. Fixed at creation.","example":"eu"},"locationHint":{"type":["string","null"],"enum":["wnam","enam","weur","eeur","apac","oc",null],"description":"Region the site’s state is placed near, or null to let Cloudflare choose. Fixed at creation.","example":"weur"},"developmentUrl":{"type":["string","null"],"description":"Qinto URL the site can be served from while its own DNS is not set up, or null when it has none.","example":"shopexamplecom.acme.workers.dev"},"deliveryMode":{"type":"string","enum":["domain","development_url"],"description":"Where the site is asked to be served from: its own `domain`, or its Qinto `development_url`.","example":"domain"},"deliveryLive":{"type":"boolean","description":"Whether the deployed worker already serves the requested `deliveryMode`. False on a site that has never deployed — call deploy — and false while a change to a deployed site has not reached the edge, which retries on its own.","example":true},"hostId":{"type":"string","description":"Host the site is provisioned under. It is fixed at creation.","example":"9b1c7f30-2d85-4e77-a6c1-0f3d8e6b5a24"}},"required":["domainId","name","domain","rootDomain","subdomain","status","jurisdiction","locationHint","developmentUrl","deliveryMode","deliveryLive","hostId"],"description":"A site a team serves through Qinto."},"CreateSiteRequest":{"type":"object","properties":{"rootDomain":{"type":"string","minLength":1,"description":"Customer domain to serve the site under, with or without `www.`.","example":"example.com"},"mode":{"type":"string","enum":["managed","self"],"description":"Who hosts the site: `managed` on Qinto’s own Cloudflare account, or `self` on one of the team’s hosts. Defaults to `managed`.","example":"managed"},"hostId":{"type":"string","format":"uuid","description":"Host to provision under. Required when `mode` is `self`, ignored otherwise.","example":"9b1c7f30-2d85-4e77-a6c1-0f3d8e6b5a24"},"name":{"type":"string","maxLength":80,"description":"Display name for the site. Defaults to the root domain. At most 80 characters.","example":"Storefront"},"subdomain":{"type":"string","maxLength":15,"description":"Label to serve the site from. Lowercase letters, digits and hyphens, at most 15 characters, and not a reserved word. A random label is chosen when omitted.","example":"shop"},"jurisdiction":{"type":"string","enum":["eu","us"],"description":"Hold the site’s data in a jurisdiction. Guaranteed for Durable Objects and object storage; other storage follows `locationHint` where it is supported, and is otherwise placed automatically. Cannot be changed later.","example":"eu"},"locationHint":{"type":"string","enum":["wnam","enam","weur","eeur","apac","oc"],"description":"Place the site’s state near a region. Cannot be changed later.","example":"weur"}},"required":["rootDomain"],"description":"The site to create, and where to host it."},"SiteDetail":{"type":"object","properties":{"domainId":{"type":"string","description":"Server-assigned unique id of the site. Address the site with it in every other operation.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"name":{"type":["string","null"],"description":"Display name of the site, as shown on the Blotout platform.","example":"Storefront"},"domain":{"type":"string","description":"Hostname Qinto serves this site on, built from its subdomain and root domain. It is fixed at creation.","example":"shop.example.com"},"rootDomain":{"type":"string","description":"Customer domain the site belongs to.","example":"example.com"},"subdomain":{"type":"string","description":"Label Qinto serves the site from, under the root domain.","example":"shop"},"status":{"type":"string","enum":["pending","active"],"description":"`pending` until the site is first deployed, then `active`. Deleted sites are not returned at all.","example":"pending"},"jurisdiction":{"type":["string","null"],"enum":["eu","us",null],"description":"Jurisdiction the site’s data is held in, or null when unrestricted. Guaranteed for Durable Objects and object storage; other storage follows `locationHint` where it is supported, and is otherwise placed automatically. Fixed at creation.","example":"eu"},"locationHint":{"type":["string","null"],"enum":["wnam","enam","weur","eeur","apac","oc",null],"description":"Region the site’s state is placed near, or null to let Cloudflare choose. Fixed at creation.","example":"weur"},"developmentUrl":{"type":["string","null"],"description":"Qinto URL the site can be served from while its own DNS is not set up, or null when it has none.","example":"shopexamplecom.acme.workers.dev"},"deliveryMode":{"type":"string","enum":["domain","development_url"],"description":"Where the site is asked to be served from: its own `domain`, or its Qinto `development_url`.","example":"domain"},"deliveryLive":{"type":"boolean","description":"Whether the deployed worker already serves the requested `deliveryMode`. False on a site that has never deployed — call deploy — and false while a change to a deployed site has not reached the edge, which retries on its own.","example":true},"hostId":{"type":"string","description":"Host the site is provisioned under. It is fixed at creation.","example":"9b1c7f30-2d85-4e77-a6c1-0f3d8e6b5a24"},"version":{"type":"object","properties":{"deployed":{"type":["string","null"],"description":"Qinto release the site’s worker runs, or null when the site has never been deployed.","example":"0.1.25"},"latest":{"type":["string","null"],"description":"Newest Qinto release a deploy would install now, or null when none is available. Deploy the site to move onto it.","example":"0.1.30"}},"required":["deployed","latest"],"description":"The release the site runs, next to the newest one available."}},"required":["domainId","name","domain","rootDomain","subdomain","status","jurisdiction","locationHint","developmentUrl","deliveryMode","deliveryLive","hostId","version"],"description":"A site a team serves through Qinto, with the release it runs."},"DeleteSiteRequest":{"type":"object","properties":{"confirmation":{"type":"string","minLength":1,"description":"The site’s hostname, typed back to confirm the deletion. Compared without regard to case or surrounding spaces.","example":"shop.example.com"}},"required":["confirmation"],"description":"Confirmation that the right site is being deleted."},"SiteDns":{"type":"object","properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecord"},"description":"Records the customer must publish; empty when the site needs none or the check could not run."},"valid":{"type":"boolean","description":"Whether the site’s hostname is verified and serving.","example":false},"required":{"type":"boolean","description":"Whether this site needs DNS at all. False when Qinto attaches the hostname itself, which never verifies through DNS.","example":true},"checked":{"type":"boolean","description":"Whether the check ran. False means the state is unknown — read `message` and `failureKind` rather than trusting `valid`.","example":true},"failureKind":{"type":["string","null"],"description":"Why the check could not run, or null when it did: `host_not_ready` and `not_configured` need a fix before retrying, anything else is transient.","example":"host_not_ready"},"message":{"type":"string","description":"What is outstanding, or why the check could not run. Empty once the site is verified.","example":"Pending SSL validation."}},"required":["records","valid","required","checked","failureKind","message"],"description":"A site’s DNS records and its current verification state."},"DnsRecord":{"type":"object","properties":{"type":{"type":"string","enum":["CNAME"],"description":"Record type to create.","example":"CNAME"},"name":{"type":"string","description":"Record name, relative to the customer’s root domain.","example":"shop"},"value":{"type":"string","description":"Value the record must carry.","example":"shop.customers.qinto-edge.com"},"note":{"type":"string","description":"Extra instruction for this record, when one applies.","example":"Disable the Proxied (orange-cloud) option."}},"required":["type","name","value"],"description":"One DNS record the customer must publish."},"SetSiteDeliveryRequest":{"type":"object","properties":{"mode":{"type":"string","enum":["domain","development_url"],"description":"Serve the site from its own `domain`, or from its Qinto `development_url` while DNS is not set up.","example":"domain"}},"required":["mode"],"description":"Where the site should be served from."},"SiteSettings":{"type":"object","properties":{"tagGlobal":{"type":["string","null"],"description":"Name of the window global the snippet binds, or null for the default `qinto` (`window.qinto`).","example":"acme"},"fallbackCookie":{"type":["string","null"],"description":"Name of the site’s own cookie Qinto reads to recover a visitor id after its own cookie expires, or null when recovery is off.","example":"_shopify_y"},"cookieSameSite":{"type":"string","enum":["strict","none"],"description":"SameSite mode of the first-party cookie Qinto recognizes returning visitors with. Allowed origins receive it only with `none`.","example":"strict"},"consent":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether each event goes only to the apps whose consent category the visitor allowed. Off sends every event to every app.","example":true}},"required":["enabled"],"description":"Consent mode."},"gpc":{"type":"boolean","description":"Whether a visitor whose browser sends Global Privacy Control is treated as opted out of marketing and sale of data.","example":true},"autoCapture":{"type":"object","properties":{"pageLoad":{"type":"boolean","description":"Whether Qinto records a page-load event without the customer instrumenting it.","example":false}},"required":["pageLoad"],"description":"Events Qinto captures without the customer instrumenting them."}},"required":["tagGlobal","fallbackCookie","cookieSameSite","consent","gpc","autoCapture"],"description":"How a site’s snippet, cookies and privacy controls behave."},"SiteApp":{"type":"object","properties":{"domainAppId":{"type":"string","description":"Server-assigned id of this installation.","example":"6c5b4a39-2817-4d6e-9f0a-1b2c3d4e5f6a"},"slug":{"type":"string","description":"Immutable slug the app runs under. Address it in the other site-app operations.","example":"facebook-capi"},"name":{"type":"string","description":"Display name of the app.","example":"Facebook CAPI"},"description":{"type":["string","null"],"description":"The app’s summary; null when not set.","example":"Send events to the Facebook Conversions API."},"flows":{"type":"array","items":{"type":"string","enum":["transform","destination"]},"description":"What the app does with events: reshape them at ingest (`transform`), receive them after commit (`destination`), or both.","example":["destination"]},"consentCategory":{"type":"string","description":"The consent category gating the app’s delivery on customer pages.","example":"marketing"},"enabled":{"type":"boolean","description":"The app-level kill switch; a disabled app receives nothing.","example":true},"desiredVersion":{"type":"string","description":"The version selected for this site.","example":"1.4.1"},"deployedVersion":{"type":["string","null"],"description":"The version the site actually runs; null while the first deployment is pending.","example":"1.4.0"},"ui":{"type":"boolean","description":"Whether the deployed version ships an embedded UI panel; false while no version is deployed.","example":false},"installCount":{"type":"integer","description":"How many installs of the app the site has.","example":2},"installLabels":{"type":"array","items":{"type":"string"},"description":"The installs’ labels, in install order.","example":["Facebook (EU)","Facebook (US)"]},"pendingGrantCount":{"type":"integer","description":"How many app-permission requests involving this app await a decision.","example":1}},"required":["domainAppId","slug","name","description","flows","consentCategory","enabled","desiredVersion","deployedVersion","ui","installCount","installLabels","pendingGrantCount"],"description":"An app installed on a site, with its versions, switch, and install summary."},"IncludedApp":{"type":"object","properties":{"appId":{"type":"string","description":"Id of the app.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"slug":{"type":"string","description":"Slug of the app, to pass to the install operation.","example":"facebook-capi"},"name":{"type":"string","description":"Display name of the app.","example":"Facebook CAPI"},"iconHash":{"type":["string","null"],"description":"Content hash of the app’s icon; null when it has none.","example":null},"publisher":{"type":"string","description":"The developer organization’s name.","example":"Acme Dev"},"bundlePurchaseId":{"type":"string","description":"The team’s purchase that covers the app on this site.","example":"9c1d2e3f-4a5b-4c6d-8e7f-0a1b2c3d4e5f"},"bundleName":{"type":"string","description":"The name of the bundle the purchase holds.","example":"Growth Stack"},"version":{"type":"string","description":"The version an install takes: the newest the site may run.","example":"1.4.1"},"consentCategory":{"type":"string","enum":["necessary","functional","analytics","marketing","salesOfData"],"description":"The consent category that version declares; `necessary` needs `acknowledgeNecessary` to install.","example":"marketing"},"legal":{"type":"object","properties":{"termsUrl":{"type":"string","description":"The developer’s terms for the app.","example":"https://example.com/legal/terms"},"privacyUrl":{"type":"string","description":"The developer’s privacy policy for the app.","example":"https://example.com/legal/privacy"}},"required":["termsUrl","privacyUrl"],"description":"The developer’s legal documents, accepted when the bundle was bought."}},"required":["appId","slug","name","iconHash","publisher","bundlePurchaseId","bundleName","version","consentCategory","legal"],"description":"An app a bundle purchase covers on the site that the site does not run yet."},"SiteVariableDefinition":{"type":"object","properties":{"name":{"type":"string","description":"The name to send the value under when configuring an install.","example":"PIXEL_ID"},"kind":{"type":"string","enum":["plain","secret"],"description":"A `plain` value is readable back; a `secret` one is write-only and never returned.","example":"plain"},"type":{"type":"string","enum":["text","password","toggle","select","multiselect"],"description":"The value it takes: a string for `text` and `password`, a boolean for `toggle`, for `select` the `value` of one of `options` or an empty string for none, and for `multiselect` a list of `options` values, empty for none.","example":"text"},"label":{"type":"string","description":"Display label the manifest gives the variable.","example":"Pixel id"},"required":{"type":"boolean","description":"Whether an install stays inactive until it has a value.","example":true},"helpText":{"type":["string","null"],"description":"One-line guidance the manifest supplies, or null when it supplies none.","example":"Found under Data sources in Meta Events Manager."},"helpUrl":{"type":["string","null"],"description":"Link to the vendor’s own documentation for this value, or null when the manifest supplies none.","example":"https://developers.example.com/pixel-id"},"options":{"type":["array","null"],"items":{"$ref":"#/components/schemas/VariableOption"},"description":"The choices of a `select` or `multiselect`, in manifest order, or null for every other type.","example":null}},"required":["name","kind","type","label","required","helpText","helpUrl","options"],"description":"One setting a site manager fills in for each install of an app."},"VariableOption":{"type":"object","properties":{"value":{"type":"string","description":"The value to send and the value stored when this option is picked.","example":"AddToCart"},"label":{"type":"string","description":"The text a form shows for this option.","example":"Add to cart"},"default":{"type":"boolean","description":"Whether a form pre-selects this option while the install has no value. The platform never stores a default on its own.","example":false}},"required":["value","label","default"],"description":"One choice of a `select` or `multiselect` variable."},"SiteAppEndpoint":{"type":"object","properties":{"path":{"type":"string","description":"The path the app declares, appended to `/app/<slug>`. A `:name` segment is a parameter matching one segment, so the URL is a pattern rather than a fixed address.","example":"/webhook"},"methods":{"type":"array","items":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"]},"description":"The HTTP methods the endpoint answers; any other method is refused before the app runs.","example":["POST"]},"auth":{"type":"string","enum":["public","token","visitor"],"description":"How the caller authenticates: `public` forwards unauthenticated for vendor webhooks, `token` requires a worker access token granting the request path the caller asked for, and that method, and `visitor` admits only the app’s own browser code, called by a site visitor.","example":"public"},"mode":{"type":"string","enum":["webhook","api"],"description":"How the request reaches the installs: `webhook` delivers it to every active install and acknowledges once, `api` passes the single install’s response through.","example":"webhook"}},"required":["path","methods","auth","mode"],"description":"An HTTP endpoint the app declares, served on the site’s own domain."},"SiteAppCapture":{"type":"object","properties":{"queryParams":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"The name read from the page.","example":"fbclid"},"type":{"type":"string","enum":["attribution","identity"],"description":"What the value is: `attribution` for a click or campaign id that ties a visit to its source, `identity` for a vendor id that names the visitor across visits.","example":"attribution"},"expiresInSeconds":{"type":"number","description":"How long a recorded value stays readable by the app, measured from the first time that value was seen. Absent means it is kept for the life of the visitor profile.","example":604800}},"required":["name","type"]},"description":"Query parameters the app records against each visitor, read from the page URL.","example":[{"name":"fbclid","type":"attribution","expiresInSeconds":604800}]},"cookies":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"The name read from the page.","example":"fbclid"},"type":{"type":"string","enum":["attribution","identity"],"description":"What the value is: `attribution` for a click or campaign id that ties a visit to its source, `identity` for a vendor id that names the visitor across visits.","example":"attribution"},"expiresInSeconds":{"type":"number","description":"How long a recorded value stays readable by the app, measured from the first time that value was seen. Absent means it is kept for the life of the visitor profile.","example":604800}},"required":["name","type"]},"description":"Cookies the app records against each visitor, read in the page. An HttpOnly cookie is never readable there.","example":[{"name":"_fbp","type":"identity"}]}},"required":["queryParams","cookies"],"description":"What the deployed version records against each visitor; both lists are empty while no version is deployed."},"SiteAppInstallDetail":{"allOf":[{"$ref":"#/components/schemas/SiteAppInstall"},{"type":"object","properties":{"values":{"type":"object","additionalProperties":{"anyOf":[{"type":"string","description":"The value of a `text`, `password` or `select` variable.","example":"1234567890"},{"type":"boolean","description":"The value of a `toggle` variable.","example":true},{"type":"array","items":{"type":"string"},"description":"The value of a `multiselect` variable: option values in manifest order.","example":["AddToCart","Purchase"]}]},"description":"The stored `plain` values, keyed by variable name. Secrets never appear here; see `secretsSet`.","example":{"PIXEL_ID":"1234567890"}}},"required":["values"]}],"description":"One install of an app on a site, with its configuration state and stored values."},"GeoFilter":{"type":"object","properties":{"include":{"type":"array","items":{"type":"string"},"description":"Locations the install runs in; empty means every location the exclude list allows.","example":["EU"]},"exclude":{"type":"array","items":{"type":"string"},"description":"Locations the install never runs in.","example":["US-CA"]}},"required":["include","exclude"],"description":"Where the install runs for visitors’ browser sessions. Each entry is an ISO 3166-1 alpha-2 country code (`SI`), `EU` for the European Union, or an ISO 3166-2 code for one of the 50 US states or the District of Columbia (`US-CA`). The install runs only when the visitor’s location is known, the include list is empty or one of its entries matches, and no exclude entry matches. A country code matches that country, `EU` matches a country in the European Union, and a state code matches a US visitor in that state. The location is unknown, and the install does not run, when the visitor’s country is not reported, when a list names a US state and a US visitor’s state is not reported, or when a list holds `EU` and the visitor’s location carries no EU flag. Server SDK events, schedules, webhooks, app endpoints, MCP tools and calls from other apps are not filtered."},"SiteAppInstall":{"type":"object","properties":{"appInstallId":{"type":"string","description":"Id of this install.","example":"8d7c6b5a-4938-4271-a605-9e8f7a6b5c4d"},"ordinal":{"type":"integer","description":"The install’s permanent ordinal; never reused after removal.","example":1},"label":{"type":"string","description":"The label every surface shows for this install.","example":"Facebook (EU)"},"enabled":{"type":"boolean","description":"The install’s own switch, beneath the app-level one.","example":true},"geoFilter":{"anyOf":[{"$ref":"#/components/schemas/GeoFilter"},{"type":"null"}],"description":"The install’s geo filter, or null when it runs in every location.","example":{"include":["EU"],"exclude":[]}},"active":{"type":"boolean","description":"Whether the install is dispatched to: both switches on and every required variable set.","example":false},"missingRequired":{"type":"array","items":{"type":"string"},"description":"Required variables the install has not completed; empty when fully configured.","example":["ACCESS_TOKEN"]},"secretsSet":{"type":"array","items":{"type":"string"},"description":"Which secret variables are set. Secret values are write-only and never returned.","example":["ACCESS_TOKEN"]}},"required":["appInstallId","ordinal","label","enabled","geoFilter","active","missingRequired","secretsSet"],"description":"One install of an app on a site and its configuration state."},"SiteAppGrant":{"type":"object","properties":{"appRpcGrantId":{"type":"string","description":"Id of the permission request.","example":"9e8d7c6b-5a49-4382-b716-0f9e8d7c6b5a"},"callerAppSlug":{"type":"string","description":"The app asking to call.","example":"facebook-capi"},"callerAppName":{"type":"string","description":"The calling app’s display name.","example":"Facebook CAPI"},"providerAppSlug":{"type":"string","description":"The app being called.","example":"consent-vault"},"providerAppName":{"type":"string","description":"The called app’s display name.","example":"Consent Vault"},"functions":{"type":"array","items":{"type":"string"},"description":"The private functions the caller wants.","example":["record"]},"status":{"type":"string","enum":["pending","approved","revoked"],"description":"The site’s decision on the request.","example":"pending"}},"required":["appRpcGrantId","callerAppSlug","callerAppName","providerAppSlug","providerAppName","functions","status"],"description":"A private app-to-app permission request on this site."},"SiteAppLifecycleDelivery":{"type":"object","properties":{"eventId":{"type":"string","description":"Stable lifecycle event id and delivery idempotency key.","example":"9e8d7c6b-5a49-4382-b716-0f9e8d7c6b5a"},"type":{"type":"string","enum":["installed","configurationChanged","enabled","disabled","versionChanged","uninstalled","deleteRequest"],"description":"Lifecycle transition, or `deleteRequest` for a delete request, sent to the app.","example":"configurationChanged"},"status":{"type":"string","enum":["pending","delivering","delivered","failed","expired","skipped"],"description":"Current best-effort delivery state.","example":"delivered"},"attempts":{"type":"integer","minimum":0,"description":"Delivery attempts made so far.","example":1},"lastError":{"type":["string","null"],"description":"Redacted last delivery error, when one exists.","example":"control_timeout"},"createdAt":{"type":"string","format":"date-time","description":"When the lifecycle event was created, as an ISO 8601 UTC timestamp.","example":"2026-08-24T10:30:00.000Z"},"deliveredAt":{"type":"string","format":"date-time","description":"When the hook completed, or null until it succeeds.","example":"2026-08-24T10:30:01.000Z"}},"required":["eventId","type","status","attempts","lastError","createdAt","deliveredAt"],"description":"Recent advisory lifecycle-hook delivery state."},"AppDependencyPlan":{"type":"object","properties":{"dependencies":{"type":"array","items":{"$ref":"#/components/schemas/AppDependency"},"description":"Every app the app needs, at any depth, in install order (each before the apps that need it)."},"rpcCalls":{"type":"array","items":{"$ref":"#/components/schemas/AppRpcCall"},"description":"The calls the app and the missing apps make to private functions of apps the site would run. A confirmed call approves their grants. Calls to public functions need no grant and are not listed."}},"required":["dependencies","rpcCalls"],"description":"With `dependencies_required`: what a confirmed call installs and the grants it approves."},"AppDependency":{"type":"object","properties":{"slug":{"type":"string","description":"Slug of the app that is needed.","example":"consent-manager"},"name":{"type":"string","description":"Display name of the app that is needed.","example":"Consent Manager"},"reason":{"type":["string","null"],"description":"Why it is needed, from the app that needs it, or else the description of the needed app; null when neither gives one.","example":"Reads the visitor’s consent state"},"neededBy":{"type":"string","description":"Slug of the app that needs it: the app being installed or another app in the plan.","example":"facebook-capi"},"state":{"type":"string","enum":["missing","installed","installed-disabled"],"description":"Whether the site has the app: `missing` (installed by a confirmed call), `installed`, or `installed-disabled` (on the site but switched off).","example":"missing"},"version":{"type":"string","description":"The version a confirmed call installs; only for a `missing` app.","example":"1.2.0"},"necessary":{"type":"boolean","description":"Whether the app runs without visitor consent, so its slug must be in `acknowledgeNecessaryDependencies`; only for a `missing` app.","example":false},"legal":{"type":"object","properties":{"termsUrl":{"type":"string","description":"The developer’s terms for this app.","example":"https://example.com/legal/terms"},"privacyUrl":{"type":"string","description":"The developer’s privacy policy for this app.","example":"https://example.com/legal/privacy"}},"required":["termsUrl","privacyUrl"],"description":"The developer’s legal documents, accepted by approving its charge; only for a `missing` app."},"charge":{"type":["object","null"],"properties":{"upToCents":{"type":"integer","minimum":0,"description":"The most the install can charge one site in a month, in US cents: the base price plus the usage cap.","example":4900},"trialDays":{"type":"integer","minimum":0,"description":"The free days before the first charge; 0 when the app has no trial.","example":14}},"required":["upToCents","trialDays"],"description":"What installing it charges, sent back in `approvedCharges` under this app’s slug to approve it; null when it charges nothing; only for a `missing` app."}},"required":["slug","name","reason","neededBy","state"],"description":"One app the installed app needs, directly or through another app it needs."},"AppRpcCall":{"type":"object","properties":{"callerAppSlug":{"type":"string","description":"Slug of the calling app: the app being installed or a missing app.","example":"facebook-capi"},"providerAppSlug":{"type":"string","description":"Slug of the app whose functions it calls.","example":"consent-manager"},"functions":{"type":"array","items":{"type":"string"},"description":"The private functions it calls, sorted by name.","example":["getConsent"]}},"required":["callerAppSlug","providerAppSlug","functions"],"description":"Calls from one app to the private functions of another, which need a grant on the site."},"AppChargeApproval":{"type":"object","properties":{"upToCents":{"type":"integer","minimum":0,"description":"The most the install can charge one site in a month, in US cents: the base price plus the usage cap.","example":4900},"trialDays":{"type":"integer","minimum":0,"description":"The free days before the first charge; 0 when the app has no trial.","example":14}},"required":["upToCents","trialDays"],"description":"With `charge_approval_required`: the current charge to send back under `appSlug` in `approvedCharges`."},"SiteAppInstallSummary":{"type":"object","properties":{"appInstallId":{"type":"string","description":"Id of this install.","example":"8d7c6b5a-4938-4271-a605-9e8f7a6b5c4d"},"ordinal":{"type":"integer","description":"The install’s permanent ordinal; never reused after removal.","example":1},"label":{"type":"string","description":"The label every surface shows for this install.","example":"Facebook (EU)"},"enabled":{"type":"boolean","description":"The install’s own switch, beneath the app-level one.","example":true},"geoFilter":{"anyOf":[{"$ref":"#/components/schemas/GeoFilter"},{"type":"null"}],"description":"The install’s geo filter, or null when it runs in every location.","example":{"include":["EU"],"exclude":[]}}},"required":["appInstallId","ordinal","label","enabled","geoFilter"],"description":"One install of an app on a site, addressable by its id."},"CreatedSiteAppInstall":{"type":"object","properties":{"appInstallId":{"type":"string","description":"Id of the install this call created.","example":"8d7c6b5a-4938-4271-a605-9e8f7a6b5c4d"},"ordinal":{"type":"integer","description":"The install’s permanent ordinal; never reused after removal.","example":2},"label":{"type":"string","description":"The label every surface shows for this install.","example":"EU pixel"},"enabled":{"type":"boolean","description":"The install’s own switch, beneath the app-level one. A new install starts enabled.","example":true},"geoFilter":{"type":"null","description":"Always null: a new install runs in every location.","example":null}},"required":["appInstallId","ordinal","label","enabled","geoFilter"],"description":"The additional install this call created, without its secrets."},"AppErrorRecord":{"type":"object","properties":{"at":{"type":"string","format":"date-time","description":"When the app failed, as an ISO 8601 UTC timestamp.","example":"2026-08-28T10:04:31.000Z"},"rowId":{"type":"string","description":"Id of this record; pair it with `at` to page.","example":"af31c0d2"},"appSlug":{"type":"string","description":"The app that failed.","example":"facebook-capi"},"appName":{"type":"string","description":"The app’s display name.","example":"Facebook CAPI"},"appInstallId":{"type":"string","description":"The installation that failed.","example":"8d7c6b5a-4938-4271-a605-9e8f7a6b5c4d"},"installLabel":{"type":"string","description":"That installation’s label.","example":"Facebook (EU)"},"appVersion":{"type":"string","description":"The app version that was serving.","example":"1.4.1"},"category":{"type":"string","description":"What kind of work failed.","example":"delivery"},"action":{"type":"string","description":"The operation the app was running.","example":"onEvent"},"description":{"type":"string","description":"What the app was doing, in its own words.","example":"send purchase"},"payload":{"type":"string","description":"The app’s own context for the failure.","example":"{\"orderId\":\"1234\"}"},"error":{"type":"string","description":"The failure itself.","example":"HTTP 429 from graph.facebook.com"}},"required":["at","rowId","appSlug","appName","appInstallId","installLabel","appVersion","category","action","description","payload","error"],"description":"One failure an app reported on this site."},"IdGraphNamespaceMetrics":{"type":"object","properties":{"identifier":{"type":"string","description":"Which identity-graph class: `anon`, one per device, or `global`, one per person.","example":"anon"},"label":{"type":"string","description":"What to show a reader for this class.","example":"Anon DO"},"buckets":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","description":"Start of the hour, as an ISO 8601 UTC timestamp.","example":"2026-10-22T09:00:00Z"},"requests":{"type":"number","description":"Requests the objects served.","example":1840},"errors":{"type":"number","description":"Requests that failed.","example":2},"wallTimeUs":{"type":"number","description":"Wall-clock time the requests took, summed, in microseconds.","example":920000},"rowsRead":{"type":"number","description":"Storage rows the objects read.","example":5400},"rowsWritten":{"type":"number","description":"Storage rows the objects wrote.","example":1200},"cpuTimeUs":{"type":"number","description":"CPU time the requests used, summed, in microseconds.","example":310000},"durationGbs":{"type":"number","description":"Billed duration, in GB-seconds.","example":0.42},"inboundWebsocketMessages":{"type":"number","description":"WebSocket messages the objects received.","example":960},"subrequests":{"type":"number","description":"Outbound requests the objects made.","example":75}},"required":["at","requests","errors","wallTimeUs","rowsRead","rowsWritten","cpuTimeUs","durationGbs","inboundWebsocketMessages","subrequests"],"description":"One hour of activity."},"description":"One bucket per hour with activity in the window, oldest first; idle hours are left out."},"totals":{"type":"object","properties":{"requests":{"type":"number","description":"Requests the objects served.","example":1840},"errors":{"type":"number","description":"Requests that failed.","example":2},"wallTimeUs":{"type":"number","description":"Wall-clock time the requests took, summed, in microseconds.","example":920000},"rowsRead":{"type":"number","description":"Storage rows the objects read.","example":5400},"rowsWritten":{"type":"number","description":"Storage rows the objects wrote.","example":1200},"cpuTimeUs":{"type":"number","description":"CPU time the requests used, summed, in microseconds.","example":310000},"durationGbs":{"type":"number","description":"Billed duration, in GB-seconds.","example":0.42},"inboundWebsocketMessages":{"type":"number","description":"WebSocket messages the objects received.","example":960},"subrequests":{"type":"number","description":"Outbound requests the objects made.","example":75}},"required":["requests","errors","wallTimeUs","rowsRead","rowsWritten","cpuTimeUs","durationGbs","inboundWebsocketMessages","subrequests"],"description":"The whole window, summed."},"previous":{"type":"object","properties":{"requests":{"type":"number","description":"Requests the objects served.","example":1840},"errors":{"type":"number","description":"Requests that failed.","example":2},"wallTimeUs":{"type":"number","description":"Wall-clock time the requests took, summed, in microseconds.","example":920000},"rowsRead":{"type":"number","description":"Storage rows the objects read.","example":5400},"rowsWritten":{"type":"number","description":"Storage rows the objects wrote.","example":1200},"cpuTimeUs":{"type":"number","description":"CPU time the requests used, summed, in microseconds.","example":310000},"durationGbs":{"type":"number","description":"Billed duration, in GB-seconds.","example":0.42},"inboundWebsocketMessages":{"type":"number","description":"WebSocket messages the objects received.","example":960},"subrequests":{"type":"number","description":"Outbound requests the objects made.","example":75}},"required":["requests","errors","wallTimeUs","rowsRead","rowsWritten","cpuTimeUs","durationGbs","inboundWebsocketMessages","subrequests"],"description":"The window of the same length before it, summed, for comparison."}},"required":["identifier","label","buckets","totals","previous"],"description":"Durable Object usage of one identity-graph class on the site."},"DeleteRequestCounts":{"type":"object","properties":{"anons":{"type":"integer","description":"How many anons (browser profiles).","example":2},"aliases":{"type":"integer","description":"How many aliases (email, phone and custom id mappings).","example":2},"persons":{"type":"integer","description":"How many person records, 0 or 1.","example":1}},"required":["anons","aliases","persons"],"description":"The identity-graph objects erased, or that a delete request would erase, by type. A second run of the same value counts only what the first one left."},"SharedSite":{"type":"object","properties":{"domainId":{"type":"string","description":"The site’s id.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"domain":{"type":"string","description":"The site’s hostname.","example":"shop.example.com"}},"required":["domainId","domain"],"description":"A site that shares the identity graph."},"ActivityEntry":{"type":"object","properties":{"activityLogId":{"type":"string","description":"Id of this entry.","example":"9e8d7c6b-5a49-4382-b716-0f9e8d7c6b5a"},"domainId":{"type":["string","null"],"description":"The site the change belongs to; null for a team-level one.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"actorUserId":{"type":["string","null"],"description":"Who made the change; null for an automated one.","example":"2b7f1a5c-8d34-4e9a-b012-3c4d5e6f7a8b"},"actorEmail":{"type":["string","null"],"description":"That person’s email as it was at the time.","example":"ada@example.com"},"actorApiTokenName":{"type":["string","null"],"description":"The credential the change came through, when it was not a browser session.","example":"CI token"},"action":{"type":"string","description":"What happened, as `<resource>.<change>`.","example":"domain_app.tool_disabled"},"metadata":{"type":"object","additionalProperties":{},"description":"Names and labels snapshotted at the time, so the entry still reads after a rename.","example":{"appSlug":"facebook-capi","toolName":"emqReport"}},"createdAt":{"type":"string","format":"date-time","description":"When it happened, as an ISO 8601 UTC timestamp.","example":"2026-08-28T10:04:31.000Z"}},"required":["activityLogId","domainId","actorUserId","actorEmail","actorApiTokenName","action","metadata","createdAt"],"description":"One recorded change in a team’s audit trail."},"BillingReport":{"anyOf":[{"$ref":"#/components/schemas/NotBilledReport"},{"$ref":"#/components/schemas/BilledReport"}],"description":"What a team pays for the Blotout platform this month, and how it pays; or that it is not billed."},"NotBilledReport":{"type":"object","properties":{"notBilled":{"type":"boolean","enum":[true],"description":"Blotout has taken the team out of automatic billing: it needs no card, is charged nothing, and gets no invoice.","example":true}},"required":["notBilled"],"description":"The report of a team that is not billed, which has no charges and no invoices."},"BilledReport":{"type":"object","properties":{"notBilled":{"type":"boolean","enum":[false],"description":"The team is billed: the rest of the report applies.","example":false},"month":{"type":"string","description":"The billing month the report covers, as `YYYY-MM` in UTC.","example":"2026-11"},"countedUntil":{"type":["string","null"],"format":"date-time","description":"The instant up to which usage is counted in `soFar`, as an ISO 8601 UTC timestamp; usage settles two days late. Null in the first two days of a month.","example":"2026-11-09T00:00:00.000Z"},"freePlatformAmountUsd":{"type":"number","description":"The core usage amount every team gets free each month, in USD.","example":5},"soFar":{"type":"object","properties":{"platformUsageUsd":{"type":"number","description":"The core usage cost this month so far, in USD at list prices.","example":12.4},"freeUsd":{"type":"number","description":"The part of it that the free platform amount covers, in USD.","example":5},"totalUsd":{"type":"number","description":"What the team owes, in USD: the cost minus the free amount.","example":7.4}},"required":["platformUsageUsd","freeUsd","totalUsd"],"description":"The charges this month so far."},"projected":{"type":["object","null"],"properties":{"platformUsageUsd":{"type":"number","description":"The core usage cost projected for the whole month, in USD at list prices.","example":12.4},"freeUsd":{"type":"number","description":"The part of it that the free platform amount covers, in USD.","example":5},"totalUsd":{"type":"number","description":"What the team owes, in USD: the cost minus the free amount.","example":7.4}},"required":["platformUsageUsd","freeUsd","totalUsd"],"description":"The projection for the whole month from recent usage, or null while the team has under 10 days of usage."},"siteCounts":{"type":"object","properties":{"charged":{"type":"number","description":"How many of the team’s sites are charged.","example":3},"notCharged":{"type":"number","description":"How many run on the team’s own Cloudflare account and are not charged.","example":1}},"required":["charged","notCharged"],"description":"The number of sites across every page of `sites`."},"sites":{"type":"object","properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/BillingSiteCost"},"description":"One page of 20 sites by hostname."},"nextCursor":{"type":["string","null"],"description":"Pass as `sitesAfter` for the next page, or null on the last one.","example":"shop.example.com"}},"required":["records","nextCursor"],"description":"The team’s live sites, and a deleted site with a cost this month."},"apps":{"type":"object","properties":{"soFarUsd":{"type":"number","description":"What every app of the team charges this month through yesterday, in USD.","example":12.6},"projectedUsd":{"type":["number","null"],"description":"The apps’ projected charge for the whole month, in USD, or null while one app has no projection yet.","example":30},"lines":{"type":"object","properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/BillingAppChargeLine"},"description":"One page of 20 apps by slug."},"nextCursor":{"type":["string","null"],"description":"Pass as `appsAfter` for the next page, or null on the last one.","example":null}},"required":["records","nextCursor"],"description":"One line per app that charged or can charge this month."}},"required":["soFarUsd","projectedUsd","lines"],"description":"What the team’s apps charge this month. The free platform amount never covers them."},"bundles":{"type":"object","properties":{"soFarUsd":{"type":"number","description":"What every bundle purchase of the team charges this month through yesterday, in USD.","example":9},"projectedUsd":{"type":["number","null"],"description":"The bundles’ projected charge for the whole month, in USD, or null while one purchase has no projection yet.","example":30},"lines":{"type":"object","properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/BillingBundleChargeLine"},"description":"One page of 20 purchases by bundle name."},"nextCursor":{"type":["string","null"],"description":"Pass as `bundlesAfter` for the next page, or null on the last one.","example":null}},"required":["records","nextCursor"],"description":"One line per bundle purchase that charged or can charge this month."}},"required":["soFarUsd","projectedUsd","lines"],"description":"What the team’s bundle purchases charge this month. The free platform amount never covers them."},"summary":{"type":"object","properties":{"soFarUsd":{"type":"number","description":"What the team owes this month so far, in USD: the core total after the free amount plus the apps and the bundles.","example":20},"projectedUsd":{"type":["number","null"],"description":"The same over the projections, or null while the core usage, an app or a bundle purchase has no projection yet.","example":46}},"required":["soFarUsd","projectedUsd"],"description":"The totals of the core usage, the apps and the bundles together, as the Billing page’s summary shows them."},"nextChargeAt":{"type":["string","null"],"format":"date-time","description":"When the team is charged next, as an ISO 8601 UTC timestamp; null for a team that has no billing yet.","example":"2026-12-06T00:00:00.000Z"},"paymentMethodOnFile":{"type":"boolean","description":"Whether the team has a payment method on file, a card or a bank account.","example":true},"paymentTerms":{"type":"string","enum":["card","invoice"],"description":"How the team pays: `card` is charged at `nextChargeAt`, `invoice` is sent an invoice.","example":"card"},"invoiceDueDays":{"type":["number","null"],"description":"On invoice terms, the days a team has to pay an invoice; null on card terms.","example":30},"invoices":{"type":"object","properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/BillingInvoice"},"description":"One page of up to 12 invoices, newest first."},"nextCursor":{"type":["string","null"],"description":"Pass as `invoicesAfter` for the next page, or null on the last one.","example":"in_1QaBcDeFgHiJkLmN"}},"required":["records","nextCursor"],"description":"The team’s past invoices."}},"required":["notBilled","month","countedUntil","freePlatformAmountUsd","soFar","projected","siteCounts","sites","apps","bundles","summary","nextChargeAt","paymentMethodOnFile","paymentTerms","invoiceDueDays","invoices"],"description":"What a billed team pays for the Blotout platform this month, and how it pays."},"BillingSiteCost":{"type":"object","properties":{"domainId":{"type":"string","description":"Id of the site.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"domain":{"type":"string","description":"Hostname of the site.","example":"shop.example.com"},"charged":{"type":"boolean","description":"Whether the site’s usage is charged; a site on the team’s own Cloudflare account is not.","example":true},"deleted":{"type":"boolean","description":"Whether the site was deleted this month; it is listed while it has a cost.","example":false},"costUsd":{"type":"number","description":"The site’s core usage cost this month so far, in USD at list prices.","example":3.2}},"required":["domainId","domain","charged","deleted","costUsd"],"description":"One site of the team and its share of this month’s core usage cost."},"BillingAppChargeLine":{"type":"object","properties":{"appId":{"type":"string","description":"Id of the app.","example":"7c1d2e3f-4a5b-4c6d-8e9f-0a1b2c3d4e5f"},"slug":{"type":"string","description":"Slug of the app.","example":"order-sync"},"name":{"type":"string","description":"Name of the app.","example":"Order Sync"},"soFarUsd":{"type":"number","description":"What the app charges this month through yesterday, in USD, over every site of the team.","example":12.6},"projectedUsd":{"type":["number","null"],"description":"The app’s projected charge for the whole month, in USD: so far, the average daily usage charge of the last 30 days for each day left, and the base fees already known for those days. Null while the app has usage on fewer than 10 of those days.","example":30},"capReached":{"type":"boolean","description":"Whether the app’s usage has reached its usage cap on one of the team’s sites this month.","example":false},"trialEndsOn":{"type":["string","null"],"description":"The UTC day the team’s free trial of the app ends, as `YYYY-MM-DD`, or null when no trial is on.","example":null},"sites":{"type":"object","properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/BillingAppSiteCharge"},"description":"One page of 20 sites by hostname."},"nextCursor":{"type":["string","null"],"description":"Pass as `appSitesAfter`, with the app’s slug as `app`, for the next page, or null on the last one.","example":null}},"required":["records","nextCursor"],"description":"The team’s sites with a charge of the app this month or an install of it that can charge."}},"required":["appId","slug","name","soFarUsd","projectedUsd","capReached","trialEndsOn","sites"],"description":"One app the team pays for this month, or can pay for, and its sites."},"BillingAppSiteCharge":{"type":"object","properties":{"domainId":{"type":"string","description":"Id of the site.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"domain":{"type":"string","description":"Hostname of the site.","example":"shop.example.com"},"deleted":{"type":"boolean","description":"Whether the site was deleted this month; it is listed while it has a charge.","example":false},"soFarUsd":{"type":"number","description":"What the app charges for the site this month so far, in USD: its base fees and usage charges.","example":4.2},"capReached":{"type":"boolean","description":"Whether the app’s usage on the site has reached its usage cap this month.","example":false}},"required":["domainId","domain","deleted","soFarUsd","capReached"],"description":"One site of the team and what the app charges for it this month."},"BillingBundleChargeLine":{"type":"object","properties":{"bundlePurchaseId":{"type":"string","description":"Id of the team’s purchase of the bundle.","example":"9b1e2c4d-7f36-4a2e-9c1d-2e5f8a7b6c3d"},"bundleId":{"type":"string","description":"Id of the bundle.","example":"4f7a1b2c-3d4e-4f5a-8b9c-0d1e2f3a4b5c"},"name":{"type":"string","description":"Name of the bundle.","example":"Growth Stack"},"soFarUsd":{"type":"number","description":"What the purchase charges this month through yesterday, in USD: its fee, its extra sites and the usage of the installs it covers.","example":9},"projectedUsd":{"type":["number","null"],"description":"The purchase’s projected charge for the whole month, in USD: so far, the average daily usage charge of the last 30 days for each day left, and the fees already known for those days. Null while a purchase with usage charges has usage on fewer than 10 of those days.","example":30},"capReached":{"type":"boolean","description":"Whether the usage the purchase covers has reached the purchase’s usage cap this month.","example":false},"extraSites":{"type":"integer","description":"The sites past the purchase’s site limit charged this month through today, each at the extra-site price. A site counts on the first day the peak number of covered sites goes over the limit in its period.","example":1},"trialEndsOn":{"type":["string","null"],"description":"The UTC day the team’s free trial of the bundle ends, as `YYYY-MM-DD`, or null when no trial is on.","example":null},"nextCharge":{"type":["object","null"],"properties":{"on":{"type":"string","description":"The UTC day of the charge, as `YYYY-MM-DD`.","example":"2026-12-01"},"amountUsd":{"type":"number","description":"The amount charged for the period that starts on that day, in USD.","example":30}},"required":["on","amountUsd"],"description":"The next day the purchase’s price is charged for a period: the first day of the next month for a monthly purchase, the anniversary for a yearly one, the one day for a one-time one. Null when the purchase has no price, its one-time price is charged, or it ends first."},"endedAt":{"type":["string","null"],"format":"date-time","description":"When the purchase ends: the first instant it no longer covers, still ahead while a cancel waits to take effect; null while active.","example":null},"sites":{"type":"object","properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/BillingBundleSite"},"description":"One page of 20 sites by hostname."},"nextCursor":{"type":["string","null"],"description":"Pass as `bundleSitesAfter`, with the purchase’s id as `bundle`, for the next page, or null on the last one.","example":null}},"required":["records","nextCursor"],"description":"The sites the purchase covers."}},"required":["bundlePurchaseId","bundleId","name","soFarUsd","projectedUsd","capReached","extraSites","trialEndsOn","nextCharge","endedAt","sites"],"description":"One bundle purchase the team pays for this month, or can pay for, and its sites."},"BillingBundleSite":{"type":"object","properties":{"domainId":{"type":"string","description":"Id of the site.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"domain":{"type":"string","description":"Hostname of the site.","example":"shop.example.com"}},"required":["domainId","domain"],"description":"One site a bundle purchase covers."},"BillingInvoice":{"type":"object","properties":{"month":{"type":"string","description":"The billing month the invoice covers, as `YYYY-MM` in UTC.","example":"2026-10"},"number":{"type":["string","null"],"description":"The invoice number, or null while it has none.","example":"QINTO-0007"},"amountCents":{"type":"number","description":"The invoice total in USD cents.","example":1200},"state":{"type":"string","enum":["open","paid","uncollectible","void"],"description":"Where the invoice stands: `open` awaits payment, `paid` is settled.","example":"paid"}},"required":["month","number","amountCents","state"],"description":"One past invoice of the team."},"BundlePurchase":{"type":"object","properties":{"bundlePurchaseId":{"type":"string","description":"Id of the purchase.","example":"9c1d2e3f-4a5b-4c6d-8e7f-0a1b2c3d4e5f"},"teamId":{"type":"string","description":"The team that holds it.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"bundleId":{"type":"string","description":"The bundle bought.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"bundleName":{"type":"string","description":"The bundle’s current name.","example":"Growth Stack"},"publisher":{"type":"string","description":"The developer organization’s name.","example":"Acme Dev"},"linkId":{"type":["string","null"],"description":"The bundle link the purchase came through; null from the app store.","example":null},"pricingModel":{"type":"string","enum":["fixed","fixed_usage","usage","free"],"description":"The pricing model copied at purchase.","example":"fixed"},"basePriceCents":{"type":["integer","null"],"description":"The price per interval copied at purchase, in US cents.","example":2900},"billingInterval":{"type":["string","null"],"enum":["monthly","yearly","one_time",null],"description":"How often the price is charged.","example":"monthly"},"trialDays":{"type":["integer","null"],"description":"The free days copied at purchase; null or 0 for none.","example":14},"siteLimit":{"anyOf":[{"type":"integer"},{"type":"string","enum":["unlimited"]}],"description":"How many sites the price covers.","example":3},"extraSitePriceCents":{"type":["integer","null"],"description":"The price per interval of each site past the limit; null when none are sold.","example":500},"services":{"type":"array","items":{"$ref":"#/components/schemas/BundleService"},"description":"The services copied at purchase."},"usageCapCents":{"type":["integer","null"],"description":"The most usage adds to the bill each month, in US cents.","example":10000},"meterTerms":{"type":"array","items":{"$ref":"#/components/schemas/BundleMeterTerm"},"description":"The priced meters copied at purchase."},"appMode":{"type":"string","enum":["selected","all","exclude"],"description":"The app mode copied at purchase.","example":"all"},"appIds":{"type":"array","items":{"type":"string"},"description":"The bundle’s stored app list copied at purchase; empty for All apps.","example":[]},"sites":{"type":"array","items":{"type":"object","properties":{"domainId":{"type":"string","description":"Id of the site.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"domain":{"type":"string","description":"The site’s hostname.","example":"q.shop.example.com"}},"required":["domainId","domain"]},"description":"The sites the purchase covers, A–Z by hostname."},"termsAcceptedByUserId":{"type":["string","null"],"description":"Who accepted the apps’ terms.","example":"1f2e3d4c-5b6a-4978-8f0e-9d8c7b6a5f4e"},"termsAcceptedAt":{"type":"string","format":"date-time","description":"When the terms were accepted.","example":"2026-11-08T12:00:00.000Z"},"chargeApprovedByUserId":{"type":["string","null"],"description":"Who approved the charge; null for a free bundle.","example":null},"chargeApprovedAt":{"type":["string","null"],"format":"date-time","description":"When the charge was approved; null for a free bundle.","example":"2026-11-08T12:00:00.000Z"},"startedAt":{"type":"string","format":"date-time","description":"The purchase instant. Charges start the next UTC day.","example":"2026-11-08T12:00:00.000Z"},"endedAt":{"type":["string","null"],"format":"date-time","description":"When the purchase ends: the first instant it no longer covers, still ahead while a cancel waits to take effect; null while active.","example":"2026-11-08T12:00:00.000Z"}},"required":["bundlePurchaseId","teamId","bundleId","bundleName","publisher","linkId","pricingModel","basePriceCents","billingInterval","trialDays","siteLimit","extraSitePriceCents","services","usageCapCents","meterTerms","appMode","appIds","sites","termsAcceptedByUserId","termsAcceptedAt","chargeApprovedByUserId","chargeApprovedAt","startedAt","endedAt"],"description":"A team’s holding of one bundle, with the terms copied when it bought it and the sites it chose."},"BundleService":{"type":"object","properties":{"name":{"type":"string","description":"Name of the service. Empty only on a bundle that isn’t published yet.","example":"Priority support"},"detail":{"type":"string","description":"What the team gets. Empty when not set.","example":"4-hour response, shared Slack channel"},"priceCents":{"type":["integer","null"],"description":"What the service costs on its own, in US cents. Null only on a bundle that isn’t published yet.","example":20000},"basis":{"type":"string","enum":["monthly","one_time"],"description":"How the price on its own is billed.","example":"monthly"}},"required":["name","detail","priceCents","basis"],"description":"A service the developer delivers, which the bundle price covers."},"BundleMeterTerm":{"type":"object","properties":{"appId":{"type":"string","description":"Id of the app that reports the meter.","example":"7f3a1c92-4b6d-4e8a-b1d3-5c9e2f7a6b10"},"key":{"type":"string","description":"Key of the meter in that app. The same key in two apps is two terms.","example":"events"},"name":{"type":"string","description":"Name of the meter on the bundle.","example":"Events"},"unit":{"type":"string","description":"Plural unit, as the bill shows it. Empty only on a bundle that isn’t published yet.","example":"events"},"includedAmount":{"type":"number","description":"Units included each month for the whole team, across its sites.","example":100000},"priceMicros":{"type":"integer","description":"Price past the included amount, in US micro-dollars.","example":500000},"perUnits":{"type":["integer","null"],"description":"How many units that price covers. Null only on a bundle that isn’t published yet.","example":1000}},"required":["appId","key","name","unit","includedAmount","priceMicros","perUnits"],"description":"What one meter of one app costs on a bundle. A meter with no term is free."},"BundleChargeApproval":{"type":"object","properties":{"feeCents":{"type":"integer","minimum":0,"description":"The most the call charges per interval, in US cents: for a purchase, the price plus the extra sites past the limit; for an added site, the extra-site price.","example":3900},"monthlyUsageCapCents":{"type":"integer","minimum":0,"description":"The most the bundle’s usage can charge in one month, in US cents, whatever the interval; 0 when it has no usage cap.","example":2000},"interval":{"type":"string","enum":["monthly","yearly","one_time"],"description":"The interval the fee is per.","example":"monthly"},"trialDays":{"type":"integer","minimum":0,"description":"The free days before the first charge; 0 when the bundle has no trial or it is over.","example":14}},"required":["feeCents","monthlyUsageCapCents","interval","trialDays"],"description":"With `charge_approval_required`: the current charge to send back as `approvedCharge`."},"BundlePurchaseApp":{"type":"object","properties":{"appId":{"type":"string","description":"Id of the app.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"slug":{"type":"string","description":"Slug of the app, to pass to the install operation.","example":"facebook-capi"},"name":{"type":"string","description":"Display name of the app.","example":"Facebook CAPI"},"iconHash":{"type":["string","null"],"description":"Content hash of the app’s icon; null when it has none.","example":null},"version":{"type":"string","description":"The version an install takes: the newest the sites may run.","example":"1.4.1"},"necessary":{"type":"boolean","description":"Whether that version runs without visitor consent, so its slug must be in `acknowledgeNecessary`.","example":false},"legal":{"type":"object","properties":{"termsUrl":{"type":"string","description":"The developer’s terms for the app.","example":"https://example.com/legal/terms"},"privacyUrl":{"type":"string","description":"The developer’s privacy policy for the app.","example":"https://example.com/legal/privacy"}},"required":["termsUrl","privacyUrl"],"description":"The developer’s legal documents, accepted when the bundle was bought."},"installedOn":{"type":"array","items":{"type":"string"},"description":"Ids of the purchase’s sites that already run the app.","example":["3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"]}},"required":["appId","slug","name","iconHash","version","necessary","legal","installedOn"],"description":"One app a bundle purchase covers, and where it is installed."},"BundleAppInstall":{"type":"object","properties":{"domainId":{"type":"string","description":"Id of the site the app was installed on.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"domain":{"type":"string","description":"The site’s hostname.","example":"q.shop.example.com"},"appSlug":{"type":"string","description":"Slug of the installed app.","example":"facebook-capi"},"version":{"type":"string","description":"The version installed.","example":"1.4.1"}},"required":["domainId","domain","appSlug","version"],"description":"One install step 2 of a bundle purchase made."},"StorageLinkSummary":{"type":"object","properties":{"storageLinkId":{"type":"string","description":"Id of the configuration.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"name":{"type":"string","description":"Name of the configuration.","example":"EU markets"},"parent":{"type":"object","properties":{"domainId":{"type":"string","description":"Id of the parent site.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"domain":{"type":"string","description":"Hostname of the parent site.","example":"www.example.com"}},"required":["domainId","domain"],"description":"The site whose storage is shared."},"childCount":{"type":"integer","description":"How many sites share the parent’s storage.","example":2},"createdAt":{"type":"string","format":"date-time","description":"When the configuration was created, as an ISO 8601 UTC timestamp.","example":"2026-09-21T10:04:31.000Z"}},"required":["storageLinkId","name","parent","childCount","createdAt"],"description":"One storage link configuration in a team’s list."},"StorageLink":{"type":"object","properties":{"storageLinkId":{"type":"string","description":"Id of the configuration.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"name":{"type":"string","description":"Name of the configuration.","example":"EU markets"},"createdAt":{"type":"string","format":"date-time","description":"When the configuration was created, as an ISO 8601 UTC timestamp.","example":"2026-09-21T10:04:31.000Z"},"updatedAt":{"type":"string","format":"date-time","description":"When the configuration was last changed, as an ISO 8601 UTC timestamp.","example":"2026-09-21T10:04:31.000Z"},"parent":{"type":"object","properties":{"domainId":{"type":"string","description":"Id of the parent site.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"domain":{"type":"string","description":"Hostname of the parent site.","example":"www.example.com"},"deployed":{"type":"boolean","description":"Whether the parent site has a deployed worker.","example":true},"sync":{"$ref":"#/components/schemas/StorageLinkSyncState"}},"required":["domainId","domain","deployed","sync"],"description":"The site whose storage is shared."},"children":{"type":"array","items":{"$ref":"#/components/schemas/StorageLinkChild"},"description":"The sites sharing the parent’s storage."}},"required":["storageLinkId","name","createdAt","updatedAt","parent","children"],"description":"A storage link configuration with its parent, children and their selections."},"StorageLinkSyncState":{"type":"object","properties":{"pending":{"type":"boolean","description":"Whether the site still has a deployment to land for its current link state.","example":false},"syncAttempts":{"type":"integer","description":"How many times the pending deployment has failed in a row.","example":0},"nextSyncAttemptAt":{"type":"string","format":"date-time","description":"When the next retry is due, or null when none is scheduled.","example":"2026-09-21T10:04:31.000Z"}},"required":["pending","syncAttempts","nextSyncAttemptAt"],"description":"Whether a site has caught up with its link configuration."},"StorageLinkChild":{"type":"object","properties":{"storageLinkMemberId":{"type":"string","description":"Id of the membership row.","example":"b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e"},"domainId":{"type":"string","description":"Id of the child site.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"domain":{"type":"string","description":"Hostname of the child site.","example":"de.example.com"},"selections":{"type":"array","items":{"type":"object","properties":{"appId":{"type":["string","null"],"description":"The app that declares the resource, or null for the identity graph.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"appSlug":{"type":["string","null"],"description":"That app’s slug, or null for the identity graph.","example":"facebook-capi"},"identifier":{"type":"string","description":"The resource identifier.","example":"cache"},"type":{"type":"string","enum":["kv","d1","r2","analytics_engine","vectorize","durable_object"],"description":"The kind of storage object.","example":"kv"}},"required":["appId","appSlug","identifier","type"]},"description":"What the child shares from the parent."},"sync":{"$ref":"#/components/schemas/StorageLinkSyncState"},"liveAliases":{"type":"integer","description":"How many of the child’s bindings still point at the parent’s storage.","example":3},"reverseBindingLive":{"type":"boolean","description":"Whether the parent’s worker still carries a binding back to this child.","example":true},"parked":{"type":"array","items":{"type":"object","properties":{"appId":{"type":"string","description":"The app that declares the resource.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"appSlug":{"type":"string","description":"That app’s slug.","example":"facebook-capi"},"identifier":{"type":"string","description":"The resource identifier.","example":"cache"},"type":{"type":"string","enum":["kv","d1","r2","analytics_engine","vectorize","durable_object"],"description":"The kind of storage object.","example":"kv"}},"required":["appId","appSlug","identifier","type"]},"description":"The child’s own app storage set aside while it shares the parent’s."}},"required":["storageLinkMemberId","domainId","domain","selections","sync","liveAliases","reverseBindingLive","parked"],"description":"One child site of a configuration."},"StorageLinkRedeploy":{"type":"object","properties":{"redeployed":{"type":"boolean","description":"Whether every affected site was redeployed at once.","example":true},"reason":{"type":["string","null"],"description":"Why a redeploy was left to the sync, or null.","example":null}},"required":["redeployed","reason"],"description":"Outcome of the immediate redeploys; a failed one is retried by the sync, so the change is saved either way."},"MeUser":{"type":["object","null"],"properties":{"userId":{"type":"string","description":"Server-assigned unique id of the authorizing user.","example":"9c2f4b71-3d58-4a06-b1e2-7f40c8a5d312"},"email":{"type":"string","description":"Email address of the authorizing user.","example":"dev@example.com"},"firstName":{"type":["string","null"],"description":"First name, or null when never provided.","example":"Ada"},"lastName":{"type":["string","null"],"description":"Last name, or null when never provided.","example":"Lovelace"}},"required":["userId","email","firstName","lastName"],"description":"The authorizing user; null for team API tokens and for OAuth tokens granted without the `profile` scope."},"MeTeamMembership":{"type":"object","properties":{"teamId":{"type":"string","description":"Server-assigned unique id of the team.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"name":{"type":["string","null"],"description":"Display name of the team, or null when it has never been named.","example":"Acme"},"createdAt":{"type":"string","format":"date-time","description":"When the team was created, as an ISO 8601 UTC timestamp.","example":"2026-06-18T00:00:00.000Z"},"scopes":{"type":"array","items":{"type":"string"},"description":"The access granted specifically in this team.","example":["team:write"]}},"required":["teamId","name","createdAt","scopes"],"description":"A team this credential may access."},"MeOrganization":{"type":"object","properties":{"organizationId":{"type":"string","description":"Server-assigned unique id of the developer organization.","example":"5e8c2d90-4b17-4f3a-9d21-8a63f0b7c154"},"name":{"type":"string","description":"Display name of the developer organization.","example":"Acme Dev"},"role":{"type":"string","description":"The user’s role in the organization: `owner`, `developer` or `member`.","example":"owner"}},"required":["organizationId","name","role"],"description":"A developer organization the authorizing user belongs to."},"CallerAppTool":{"type":"object","properties":{"mcpName":{"type":"string","description":"The tool’s name in the shared assistant namespace.","example":"facebook-capi_emqReport"},"appSlug":{"type":"string","description":"The app that contributes the tool.","example":"facebook-capi"},"appName":{"type":"string","description":"That app’s display name.","example":"Facebook CAPI"},"name":{"type":"string","description":"The tool’s own name, without the app prefix.","example":"emqReport"},"title":{"type":"string","description":"A short name to show a reader.","example":"Event match quality report"},"description":{"type":"string","description":"What the tool does, written by the app’s developer.","example":"Reads this install and reports its event match quality score."},"annotations":{"type":"object","properties":{"readOnlyHint":{"type":"boolean","description":"True only when every reachable version is read-only.","example":true},"destructiveHint":{"type":"boolean","description":"True as soon as any reachable version says so.","example":false},"idempotentHint":{"type":"boolean","description":"True only when every reachable version says so.","example":true}},"required":["readOnlyHint","destructiveHint","idempotentHint"],"description":"The tool’s advertised behaviour, merged conservatively across the versions in play."},"inputSchema":{"type":"object","additionalProperties":{},"description":"The JSON Schema of everything the call takes, including `teamId`, `siteId` and `installId`.","example":{"type":"object","properties":{},"required":["teamId","siteId"]}},"sites":{"type":"array","items":{"$ref":"#/components/schemas/AppToolSite"},"description":"The sites this tool can be run against."}},"required":["mcpName","appSlug","appName","name","title","description","annotations","inputSchema","sites"],"description":"One app tool the caller can reach, deduplicated across their sites."},"AppToolSite":{"type":"object","properties":{"teamId":{"type":"string","description":"The team that owns the site.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"domainId":{"type":"string","description":"The site to pass as `siteId`.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"domain":{"type":"string","description":"The site’s hostname, for showing a reader which site this is.","example":"q.shop.example.com"}},"required":["teamId","domainId","domain"],"description":"A site the caller may run this tool against."},"CallerAppToolWarning":{"type":"object","properties":{"appSlug":{"type":"string","description":"The app whose tool is withheld.","example":"facebook-capi"},"toolName":{"type":"string","description":"The tool that is not listed.","example":"emqReport"},"reason":{"type":"string","enum":["schema_divergence","absent_in_version","disabled_on_site"],"description":"Why it is withheld: the reachable versions describe different arguments, one of them does not declare it, or it is switched off everywhere.","example":"schema_divergence"},"sites":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/AppToolSite"},{"type":"object","properties":{"version":{"type":"string","description":"The version that site serves.","example":"1.4.1"}},"required":["version"]}],"description":"A site the caller may run this tool against."},"description":"The sites and versions involved."}},"required":["appSlug","toolName","reason","sites"],"description":"A tool that exists but is not advertised, and why."},"InstallableApp":{"type":"object","properties":{"slug":{"type":"string","description":"The app’s slug, to pass as `appSlug` when installing.","example":"facebook-capi"},"name":{"type":"string","description":"The app’s display name.","example":"Facebook CAPI"},"description":{"type":["string","null"],"description":"What the app does, or null when the developer gave no description.","example":"Sends events to Meta."},"organizationId":{"type":"string","description":"The developer organization that owns the app.","example":"5e8c2d90-4b17-4f3a-9d21-8a63f0b7c154"},"organizationName":{"type":"string","description":"That organization’s display name.","example":"Acme Dev"},"latestVersion":{"type":"string","description":"The highest published version, which an install takes by default.","example":"1.4.1"},"consentCategory":{"type":"string","description":"The visitor consent the app runs under; a `necessary` app needs an acknowledgement before its first install.","example":"marketing"},"multipleInstalls":{"type":"boolean","description":"Whether one site can install the app more than once.","example":false},"variables":{"type":"array","items":{"$ref":"#/components/schemas/SiteVariableDefinition"},"description":"The settings each install takes, as the latest version declares them."}},"required":["slug","name","description","organizationId","organizationName","latestVersion","consentCategory","multipleInstalls","variables"],"description":"An app the caller may install on a site they manage apps on."},"App":{"type":"object","properties":{"appId":{"type":"string","description":"Server-assigned unique id of the app. Address the app with it in the get, update and delete operations.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"organizationId":{"type":"string","description":"Id of the organization that owns the app.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"slug":{"type":"string","description":"Immutable identifier the app is addressed by everywhere it runs. Fixed at creation and reserved forever, even after the app is deleted.","example":"facebook-capi"},"name":{"type":"string","description":"Display name of the app, as shown on the Blotout platform.","example":"Facebook CAPI"},"description":{"type":["string","null"],"description":"Optional summary of what the app does, shown wherever the app is listed. Null when not set.","example":"Send events to the Facebook Conversions API."},"createdAt":{"type":"string","format":"date-time","description":"When the app was registered, as an ISO 8601 UTC timestamp.","example":"2026-08-17T00:00:00.000Z"},"updatedAt":{"type":"string","format":"date-time","description":"When the app was last updated, as an ISO 8601 UTC timestamp.","example":"2026-08-17T00:00:00.000Z"}},"required":["appId","organizationId","slug","name","description","createdAt","updatedAt"],"description":"A developer app owned by an organization. Versions of it are pushed with the Qinto CLI and installed on sites."},"AppVersion":{"type":"object","properties":{"appVersionId":{"type":"string","description":"Server-assigned unique id of the version. Address it in the artifact, finalize, and cancel operations.","example":"7d8e9f0a-1b2c-4d3e-9f4a-5b6c7d8e9f0a"},"version":{"type":"string","description":"The allocated semver. Fixed once allocated; a retried publish resumes onto it instead of allocating another.","example":"1.4.1"},"status":{"type":"string","enum":["draft","ready"],"description":"Lifecycle state: `draft` until the publish finalizes it, `ready` once its artifacts are verified and frozen.","example":"draft"},"readyAt":{"type":"string","format":"date-time","description":"When the version was frozen as an ISO 8601 UTC timestamp; null while it is a draft.","example":"2026-08-17T12:00:00.000Z"},"createdAt":{"type":"string","format":"date-time","description":"When the version was allocated, as an ISO 8601 UTC timestamp.","example":"2026-08-17T12:00:00.000Z"}},"required":["appVersionId","version","status","readyAt","createdAt"],"description":"One immutable version of a developer app, published with the Qinto CLI."},"AppPublishMeterWarning":{"type":"object","properties":{"code":{"type":"string","enum":["priced_meter_undeclared"],"description":"A meter the app’s pricing prices that the version does not declare in `billing.meters`.","example":"priced_meter_undeclared"},"meterKey":{"type":"string","description":"The meter key the warning is about.","example":"events_sent"},"message":{"type":"string","description":"The warning as a sentence to show the developer.","example":"Meter \"events_sent\" has a price, but version 1.4.1 does not declare it in billing.meters, so it gets no usage and is not billed."}},"required":["code","meterKey","message"],"description":"A priced meter that gets no usage from this version."},"AppPublishQueueWarning":{"type":"object","properties":{"code":{"type":"string","enum":["queue_removed"],"description":"A queue the previous version declares that this version removes.","example":"queue_removed"},"queueIdentifier":{"type":"string","description":"The identifier of the removed queue.","example":"order-events"},"message":{"type":"string","description":"The warning as a sentence to show the developer.","example":"Version 1.4.1 removes queue \"order-events\", which version 1.4.0 declares. A site that moves to version 1.4.1 deletes the queue and the messages still in it."}},"required":["code","queueIdentifier","message"],"description":"A queue this version removes; a site that moves to it loses the messages in the queue."},"AppPublishSinkBatchWarning":{"type":"object","properties":{"code":{"type":"string","enum":["sink_batch_changed"],"description":"A pipeline sink whose `batch` differs from the previous version.","example":"sink_batch_changed"},"pipelineIdentifier":{"type":"string","description":"The identifier of the pipeline.","example":"stream"},"sinkIdentifier":{"type":"string","description":"The identifier of the sink.","example":"events"},"message":{"type":"string","description":"The warning as a sentence to show the developer.","example":"Version 1.4.1 changes the batch values of sink \"events\" on pipeline \"stream\". They apply only to sinks created after this version: a sink that exists on a site keeps the values it was created with."}},"required":["code","pipelineIdentifier","sinkIdentifier","message"],"description":"A sink whose batch values changed; a sink that exists on a site keeps the values it was created with."},"AppVariable":{"type":"object","properties":{"name":{"type":"string","description":"Name the app’s manifest declares the variable under, and the name to send when setting its value.","example":"META_APP_SECRET"},"kind":{"type":"string","enum":["plain","secret"],"description":"Where the value is stored: a `plain` value is readable back, a `secret` one is write-only and never returned.","example":"secret"},"type":{"type":"string","enum":["text","password"],"description":"How a form should render the input for this variable.","example":"password"},"label":{"type":"string","description":"Display label the manifest gives the variable.","example":"Meta app secret"},"required":{"type":"boolean","description":"Whether a version that declares this variable refuses to publish until it has a value.","example":true},"helpText":{"type":["string","null"],"description":"One-line guidance the manifest supplies, or null when it supplies none.","example":"Found under App settings in the Meta developer console."},"helpUrl":{"type":["string","null"],"description":"Link to the vendor’s own documentation for this value, or null when the manifest supplies none.","example":"https://developers.example.com/app-secret"},"value":{"type":["string","null"],"description":"The stored value for a `plain` variable, or null when it has none. Always null for a `secret` variable.","example":"https://api.example.com"},"set":{"type":"boolean","description":"Whether a value is stored for this variable.","example":true}},"required":["name","kind","type","label","required","helpText","helpUrl","value","set"],"description":"One app-scope setting: a value the developer sets once for the app, delivered identically to every site that installs it. Distinct from a site app’s per-install variables, which a site manager fills in."},"AppSite":{"type":"object","properties":{"domainAppId":{"type":"string","description":"Server-assigned id of the app’s installation record on this site.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"domainId":{"type":"string","description":"Id of the site. Address the site with it in the get site and configure install operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"domain":{"type":"string","description":"The site’s first-party hostname the app runs under.","example":"q.shop.example.com"},"version":{"type":"string","description":"The app version the site is on.","example":"1.4.1"},"enabled":{"type":"boolean","description":"Whether the site manager has the app switched on.","example":true},"installedAt":{"type":"string","format":"date-time","description":"When the site installed the app, as an ISO 8601 UTC timestamp.","example":"2026-08-17T12:00:00.000Z"}},"required":["domainAppId","domainId","domain","version","enabled","installedAt"],"description":"One live site running a developer app, as the app’s developer sees it."},"AppSiteDetail":{"type":"object","properties":{"domainAppId":{"type":"string","description":"Server-assigned id of the app’s installation record on this site.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"domainId":{"type":"string","description":"Id of the site. Address the site with it in the get site and configure install operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"domain":{"type":"string","description":"The site’s first-party hostname the app runs under.","example":"q.shop.example.com"},"version":{"type":"string","description":"The app version the site is on.","example":"1.4.1"},"enabled":{"type":"boolean","description":"Whether the site manager has the app switched on.","example":true},"installedAt":{"type":"string","format":"date-time","description":"When the site installed the app, as an ISO 8601 UTC timestamp.","example":"2026-08-17T12:00:00.000Z"},"variables":{"type":"array","items":{"$ref":"#/components/schemas/AppSiteVariable"},"description":"The developer-owned variables the site’s version declares, in manifest order. Empty when it declares none."},"installs":{"type":"array","items":{"$ref":"#/components/schemas/AppSiteInstall"},"description":"The live installations on the site, in ordinal order."}},"required":["domainAppId","domainId","domain","version","enabled","installedAt","variables","installs"],"description":"A site running the app, its installations, and the developer-owned variables on each."},"AppSiteVariable":{"type":"object","properties":{"name":{"type":"string","description":"Name the app’s manifest declares the variable under, and the name to send when setting its value.","example":"BETA_CHECKOUT"},"kind":{"type":"string","enum":["plain","secret"],"description":"Where the value is stored: a `plain` value is readable back, a `secret` one is write-only and never returned.","example":"plain"},"type":{"type":"string","enum":["text","password","toggle","select","multiselect"],"description":"How a form should render the input. A `toggle` takes a boolean value; a `select` takes the `value` of one of `options`, or an empty string for none; a `multiselect` takes a list of `options` values, empty for none; the others take a string.","example":"toggle"},"label":{"type":"string","description":"Display label the manifest gives the variable.","example":"Beta checkout"},"browser":{"type":"boolean","description":"Whether the value also ships into the site’s browser bundle.","example":false},"helpText":{"type":["string","null"],"description":"One-line guidance the manifest supplies, or null when it supplies none.","example":"Turns on the redesigned checkout for this site."},"helpUrl":{"type":["string","null"],"description":"Link to further documentation, or null when the manifest supplies none.","example":"https://developers.example.com/beta-checkout"},"options":{"type":["array","null"],"items":{"$ref":"#/components/schemas/VariableOption"},"description":"The choices of a `select` or `multiselect`, in manifest order, or null for every other type.","example":null}},"required":["name","kind","type","label","browser","helpText","helpUrl","options"],"description":"One per-install setting the app’s manifest hands to the developer (`owner: \"developer\"`). A site manager never sees it; the developer sets it per install."},"AppSiteInstall":{"type":"object","properties":{"appInstallId":{"type":"string","description":"Id of the installation. Address it with the configure install operation.","example":"8d7c6b5a-4938-4271-a605-9e8f7a6b5c4d"},"ordinal":{"type":"integer","description":"Position of the installation on the site, from 1.","example":1},"label":{"type":"string","description":"The label the site manager gave the installation.","example":"EU pixel"},"enabled":{"type":"boolean","description":"Whether the site manager has this installation switched on.","example":true},"variables":{"type":"object","additionalProperties":{"anyOf":[{"type":"string","description":"The value of a `text`, `password` or `select` variable.","example":"v2"},{"type":"boolean","description":"The value of a `toggle` variable.","example":true},{"type":"array","items":{"type":"string"},"description":"The value of a `multiselect` variable: option values in manifest order.","example":["AddToCart","Purchase"]}]},"description":"The stored values of the developer-owned `plain` variables, keyed by name. A name with no value is absent.","example":{"BETA_CHECKOUT":true}},"secretsSet":{"type":"array","items":{"type":"string","description":"A developer-owned secret variable name.","example":"BETA_KEY"},"description":"The developer-owned `secret` variables that hold a value. Values are never returned."}},"required":["appInstallId","ordinal","label","enabled","variables","secretsSet"],"description":"One installation of the app on a site, with the developer-owned state of its variables."},"Bundle":{"type":"object","properties":{"bundleId":{"type":"string","description":"Server-assigned unique id of the bundle. Address the bundle with it in the get, update and delete operations.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"organizationId":{"type":"string","description":"Id of the organization that owns the bundle.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"name":{"type":"string","description":"Display name of the bundle.","example":"Growth Stack"},"description":{"type":["string","null"],"description":"One-line description of what a team gets. Null when not set.","example":"Everything a store needs to measure its marketing."},"longDescription":{"type":["string","null"],"description":"Longer description with its line breaks kept. Null when not set.","example":"Who the bundle is for.\n\nHow support works."},"status":{"type":"string","enum":["draft","live","paused","retired"],"description":"Where the bundle is in its life: `draft` is not published yet, `live` is on sale, `paused` is stopped by Blotout, and `retired` is no longer sold.","example":"draft"},"audience":{"type":"string","enum":["public","private"],"description":"Who can reach the bundle: `public` is offered in the app store, and `private` only through bundle links. It locks when the bundle first leaves Draft.","example":"private"},"appMode":{"type":"string","enum":["selected","all","exclude"],"description":"How the bundle picks its apps: `selected` takes the listed apps, `all` takes every eligible app of the organization, and `exclude` takes every eligible app except the listed ones. `all` and `exclude` add future apps.","example":"selected"},"pricingModel":{"type":"string","enum":["fixed","fixed_usage","usage","free"],"description":"How the bundle charges: `fixed` is a base price, `fixed_usage` a base price and usage, `usage` only usage, and `free` nothing. A new bundle without it is `fixed`.","example":"fixed"},"basePriceCents":{"type":["integer","null"],"description":"Base price per team, in US cents. Null when not set.","example":7200000},"billingInterval":{"type":["string","null"],"enum":["monthly","yearly","one_time",null],"description":"How often the base price is billed. Null when not set.","example":"yearly"},"trialDays":{"type":["integer","null"],"description":"Length of the free trial in days. Null when not set.","example":14},"siteLimit":{"anyOf":[{"type":"integer","description":"The number of sites a team can use the bundle on.","example":3},{"type":"string","enum":["unlimited"],"description":"No site limit.","example":"unlimited"}],"description":"How many sites a team can use the bundle on. A new bundle has 1.","example":3},"extraSitePriceCents":{"type":["integer","null"],"description":"Price of each site past the limit in US cents, billed like the base price. Null when extra sites aren’t sold.","example":50000},"services":{"type":"array","items":{"$ref":"#/components/schemas/BundleService"},"description":"The services the bundle price covers."},"usageCapCents":{"type":["integer","null"],"description":"The most usage can add to a team’s bill each month, in US cents. Null when not set.","example":50000},"meterTerms":{"type":"array","items":{"$ref":"#/components/schemas/BundleMeterTerm"},"description":"The priced meters. Any other meter the apps report is free."},"listedApps":{"type":"array","items":{"$ref":"#/components/schemas/BundleAppRef"},"description":"The stored app list of a `selected` or `exclude` bundle. Empty for `all`."},"apps":{"type":"array","items":{"$ref":"#/components/schemas/BundleAppRef"},"description":"The apps the bundle holds right now, computed on read: a `public` bundle takes only apps in the app store, and a `private` bundle takes every app with a published version that isn’t suspended."},"canBeSold":{"type":"boolean","description":"Whether the bundle can be sold right now, computed on read: it is `live`, holds at least one app, and none of the apps a `selected` bundle lists is unavailable.","example":true},"needsAttention":{"type":"boolean","description":"Whether the bundle’s apps stop it from selling, computed on read: on a `live` or `paused` bundle, an app a `selected` bundle lists is unavailable, or no app remains. Always false on `draft` and `retired`. It clears by itself when Blotout lifts a suspension or approves a new store submission.","example":false},"attentionReason":{"type":["string","null"],"description":"Why the bundle needs attention, written for the developer. Null when `needsAttention` is false.","example":"No apps remain, so this bundle can’t be sold. Unavailable: Facebook CAPI."},"affectedApps":{"type":"array","items":{"$ref":"#/components/schemas/BundleAppRef"},"description":"The unavailable apps behind `needsAttention`, empty when it is false: the apps a `selected` bundle lists that were removed from the app store, suspended or taken down, or the apps of an `all` or `exclude` bundle that Blotout removed or suspended. May be empty when `needsAttention` is true, if no Blotout action explains the missing apps; `attentionReason` still says why."},"pauseReason":{"type":["string","null"],"description":"Why Blotout paused the bundle. Null unless the status is `paused`, and a lift clears it.","example":"The listing promises a discount the price does not give."},"createdAt":{"type":"string","format":"date-time","description":"When the bundle was created, as an ISO 8601 UTC timestamp.","example":"2026-11-05T00:00:00.000Z"},"updatedAt":{"type":"string","format":"date-time","description":"When the bundle was last updated, as an ISO 8601 UTC timestamp.","example":"2026-11-05T00:00:00.000Z"}},"required":["bundleId","organizationId","name","description","longDescription","status","audience","appMode","pricingModel","basePriceCents","billingInterval","trialDays","siteLimit","extraSitePriceCents","services","usageCapCents","meterTerms","listedApps","apps","canBeSold","needsAttention","attentionReason","affectedApps","pauseReason","createdAt","updatedAt"],"description":"An offer that sells several of an organization’s apps to a team on one subscription line."},"BundleAppRef":{"type":"object","properties":{"appId":{"type":"string","description":"Unique id of the app.","example":"7f3a1c92-4b6d-4e8a-b1d3-5c9e2f7a6b10"},"name":{"type":"string","description":"Display name of the app.","example":"Facebook CAPI"}},"required":["appId","name"],"description":"An app of the organization, by id and name."},"BundlePublishIssue":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable code of this issue.","example":"invalid_name"},"message":{"type":"string","description":"Human-readable text for this issue, intended for display.","example":"Name must be between 1 and 100 characters."}},"required":["code","message"],"description":"One thing the publish checks found in a bundle."},"BundleApp":{"type":"object","properties":{"appId":{"type":"string","description":"Unique id of the app. Pass it in `appIds` on a bundle.","example":"7f3a1c92-4b6d-4e8a-b1d3-5c9e2f7a6b10"},"name":{"type":"string","description":"Display name of the app.","example":"Facebook CAPI"},"inStore":{"type":"boolean","description":"Whether the app is in the app store. A `public` bundle can use only these apps.","example":true},"pricing":{"type":"object","properties":{"model":{"type":"string","enum":["fixed","fixed_usage","usage","free"],"description":"The app’s own pricing model. An app that was never priced is `free`.","example":"fixed"},"basePriceCents":{"type":["integer","null"],"description":"The app’s own base price in US cents, or null when it has none.","example":4900}},"required":["model","basePriceCents"],"description":"What the app costs on its own."},"meterKeys":{"type":"object","properties":{"public":{"type":"array","items":{"type":"string","description":"One meter key.","example":"events"},"description":"Keys of the billing meters in the latest approved version, the ones a `public` bundle reads. Empty with no approved version."},"private":{"type":"array","items":{"type":"string","description":"One meter key.","example":"events"},"description":"Keys of the billing meters in the latest published version, the ones a `private` bundle reads."}},"required":["public","private"],"description":"The meter keys the app declares, by the audience that reads them."}},"required":["appId","name","inStore","pricing","meterKeys"],"description":"A published app of the organization, as a bundle can use it."},"BundleLink":{"type":"object","properties":{"linkId":{"type":"string","description":"Server-assigned unique id of the link.","example":"5d2c8e71-3f4a-4b90-8c16-e7a9d0b2f345"},"bundleId":{"type":"string","description":"Id of the bundle the link belongs to.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"label":{"type":"string","description":"What the developer calls the link.","example":"Acme partner offer"},"limit":{"anyOf":[{"type":"integer","description":"How many teams can buy through the link.","example":25},{"type":"string","enum":["unlimited"],"description":"No limit.","example":"unlimited"}],"description":"How many teams can buy through the link. It can be below `useCount`, which only stops further purchases.","example":25},"token":{"type":"string","description":"The token in the link’s URL. It stays readable, so the link can be copied again at any time.","example":"3f9a1c7e5b2d4806a1e3c5f7092b4d6e8f0a1c3e5b7d9f1a2c4e6b8d0f2a4c6e"},"url":{"type":"string","description":"The URL to send to a team.","example":"https://platform.blotout.io/bundles/link?token=3f9a1c7e5b2d4806a1e3c5f7092b4d6e8f0a1c3e5b7d9f1a2c4e6b8d0f2a4c6e"},"useCount":{"type":"integer","description":"How many teams have bought through the link.","example":0},"revokedAt":{"type":["string","null"],"format":"date-time","description":"When the link was revoked, as an ISO 8601 UTC timestamp. Null while it is not revoked.","example":"2026-11-05T00:00:00.000Z"},"createdByUserId":{"type":["string","null"],"description":"Id of the user who created the link. Null once that user is deleted.","example":"c7d1e2f3-4a5b-4c6d-8e9f-0a1b2c3d4e5f"},"createdAt":{"type":"string","format":"date-time","description":"When the link was created, as an ISO 8601 UTC timestamp.","example":"2026-11-05T00:00:00.000Z"}},"required":["linkId","bundleId","label","limit","token","url","useCount","revokedAt","createdByUserId","createdAt"],"description":"A link that offers a private bundle to whoever holds it."},"StoreAppCard":{"type":"object","properties":{"slug":{"type":"string","description":"The app’s slug, to pass as `appSlug`.","example":"facebook-capi"},"name":{"type":"string","description":"The app’s display name.","example":"Facebook CAPI"},"tagline":{"type":"string","description":"One line on what the app does.","example":"Send conversions to Meta from your server."},"publisher":{"type":"string","description":"Display name of the organization that publishes the app.","example":"Acme Dev"},"categories":{"type":"array","items":{"type":"string"},"description":"The categories the app is listed in.","example":["advertising"]}},"required":["slug","name","tagline","publisher","categories"],"description":"An app in the app store, as a search result."},"StoreApp":{"type":"object","properties":{"slug":{"type":"string","description":"The app’s slug, to pass as `appSlug`.","example":"facebook-capi"},"name":{"type":"string","description":"The app’s display name.","example":"Facebook CAPI"},"tagline":{"type":"string","description":"One line on what the app does.","example":"Send conversions to Meta from your server."},"publisher":{"type":"string","description":"Display name of the organization that publishes the app.","example":"Acme Dev"},"categories":{"type":"array","items":{"type":"string"},"description":"The categories the app is listed in.","example":["advertising"]},"description":{"type":"string","description":"The long description of the app.","example":"Sends purchase and lead events to Meta."},"features":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"The feature’s heading.","example":"Server-side delivery"},"text":{"type":"string","description":"What the feature does.","example":"Events reach Meta even when the browser blocks the pixel."}},"required":["title","text"]},"description":"The features the publisher highlights, in listing order."},"supportContact":{"type":"string","description":"Where to ask the publisher for help: an email address or a URL.","example":"support@acme.example"},"websiteUrl":{"type":["string","null"],"description":"The publisher’s page for the app, or null when none is given.","example":"https://acme.example/capi"},"documentationUrl":{"type":["string","null"],"description":"The app’s documentation, or null when none is given.","example":"https://acme.example/docs/capi"},"screenshots":{"type":"array","items":{"type":"object","properties":{"caption":{"type":"string","description":"What the screenshot shows.","example":"The event overview."}},"required":["caption"]},"description":"The captions of the listing’s screenshots, in listing order. The API does not serve the images."},"facts":{"$ref":"#/components/schemas/StoreAppFacts"},"versions":{"type":"array","items":{"type":"object","properties":{"version":{"type":"string","description":"The version number.","example":"1.4.1"},"approvedAt":{"type":["string","null"],"format":"date-time","description":"When the version was approved for the app store; null when the time was not recorded.","example":"2026-09-30T12:00:00.000Z"}},"required":["version","approvedAt"]},"description":"The approved versions, newest first, 50 at most."}},"required":["slug","name","tagline","publisher","categories","description","features","supportContact","websiteUrl","documentationUrl","screenshots","facts","versions"],"description":"An app in the app store, with its full listing."},"StoreAppFacts":{"type":"object","properties":{"version":{"type":"string","description":"The newest approved version, which the other facts describe.","example":"1.4.1"},"capabilities":{"type":"object","properties":{"api":{"type":"array","items":{"type":"string"},"description":"The site-API scopes the app may call with its own token.","example":["track"]},"data":{"type":"array","items":{"type":"string"},"description":"The event-data buckets delivered to the app.","example":["customProperties"]}},"required":["api","data"],"description":"What the app may do and see on a site."},"consentCategory":{"type":"string","description":"The visitor consent the app runs under.","example":"marketing"},"flows":{"type":"array","items":{"type":"string"},"description":"Where the app plugs into the event pipeline.","example":["destination"]},"vendors":{"type":"array","items":{"type":"string"},"description":"The vendor accounts an install connects to.","example":["Meta"]},"tools":{"type":"array","items":{"type":"string"},"description":"The tools the app offers to AI assistants.","example":["list_audiences"]},"roles":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"The role’s name.","example":"viewer"},"description":{"type":"string","description":"What the role may do in the app, when the app says.","example":"Reads reports."}},"required":["key"]},"description":"The app roles a team can give its members; absent when the app declares none."},"runsCustomCode":{"type":"boolean","description":"Whether the app runs code that is not part of the app, such as code a merchant writes or an AI generates, in an isolated sandbox.","example":false},"termsUrl":{"type":"string","description":"The publisher’s terms of service.","example":"https://acme.example/terms"},"privacyUrl":{"type":"string","description":"The publisher’s privacy policy.","example":"https://acme.example/privacy"}},"required":["version","capabilities","consentCategory","flows","vendors","tools","runsCustomCode","termsUrl","privacyUrl"],"description":"What the newest approved version declares."},"StoreBundle":{"type":"object","properties":{"bundleId":{"type":"string","description":"Unique id of the bundle.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"name":{"type":"string","description":"Display name of the bundle.","example":"Growth Stack"},"description":{"type":["string","null"],"description":"One-line description of what a team gets. Null when not set.","example":"Everything a store needs."},"longDescription":{"type":["string","null"],"description":"Longer description with its line breaks kept. Null when not set.","example":"Who the bundle is for."},"publisher":{"type":"string","description":"Display name of the organization that sells the bundle.","example":"Acme Dev"},"audience":{"type":"string","enum":["public","private"],"description":"`public` is offered in the app store; `private` is reached only through a bundle link.","example":"public"},"pricingModel":{"type":"string","enum":["fixed","fixed_usage","usage","free"],"description":"How the bundle charges: `fixed` is a base price, `fixed_usage` a base price and usage, `usage` only usage, and `free` nothing.","example":"fixed"},"basePriceCents":{"type":["integer","null"],"description":"Base price per team, in US cents. Null when the model has none.","example":2900},"billingInterval":{"type":["string","null"],"enum":["monthly","yearly","one_time",null],"description":"How often the base price is billed. Null when the model has none.","example":"monthly"},"trialDays":{"type":["integer","null"],"description":"Length of the free trial in days. Null or 0 when there is none.","example":14},"siteLimit":{"anyOf":[{"type":"integer","description":"The number of sites a team can use the bundle on.","example":3},{"type":"string","enum":["unlimited"],"description":"No site limit.","example":"unlimited"}],"description":"How many sites a team can use the bundle on.","example":3},"extraSitePriceCents":{"type":["integer","null"],"description":"Price of each site past the limit in US cents, billed like the base price. Null when extra sites aren’t sold.","example":500},"services":{"type":"array","items":{"$ref":"#/components/schemas/BundleService"},"description":"The services the bundle price covers."},"usageCapCents":{"type":["integer","null"],"description":"The most usage can add to a team’s bill each month, in US cents. Null when the model has no usage.","example":10000},"meterTerms":{"type":"array","items":{"$ref":"#/components/schemas/BundleMeterTerm"},"description":"The priced meters. Any other meter the apps report is free."},"apps":{"type":"array","items":{"$ref":"#/components/schemas/StoreBundleApp"},"description":"The apps the bundle holds right now, A–Z by name."},"comparison":{"$ref":"#/components/schemas/BundlePriceComparison"}},"required":["bundleId","name","description","longDescription","publisher","audience","pricingModel","basePriceCents","billingInterval","trialDays","siteLimit","extraSitePriceCents","services","usageCapCents","meterTerms","apps","comparison"],"description":"A bundle a team can buy: several apps on one line of its bill, for the sites it chooses."},"StoreBundleApp":{"type":"object","properties":{"appId":{"type":"string","description":"Unique id of the app.","example":"7f3a1c92-4b6d-4e8a-b1d3-5c9e2f7a6b10"},"slug":{"type":"string","description":"The app’s slug, to pass as `appSlug` to the app store app operations.","example":"facebook-capi"},"name":{"type":"string","description":"Display name of the app.","example":"Facebook CAPI"},"pricingModel":{"type":"string","enum":["fixed","fixed_usage","usage","free"],"description":"How the app charges on its own.","example":"fixed"},"basePriceCents":{"type":"integer","description":"The app’s own monthly price per site in US cents; 0 when it has no base price.","example":1900},"legal":{"type":"object","properties":{"termsUrl":{"type":"string","description":"The developer’s terms for the app.","example":"https://acme.example/terms"},"privacyUrl":{"type":"string","description":"The developer’s privacy policy for the app.","example":"https://acme.example/privacy"}},"required":["termsUrl","privacyUrl"],"description":"The legal links a buyer accepts when buying the bundle."}},"required":["appId","slug","name","pricingModel","basePriceCents","legal"],"description":"An app a bundle holds right now, with what it costs on its own."},"BundlePriceComparison":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["no_base_price"],"description":"The pricing model has no base price to compare.","example":"no_base_price"}},"required":["kind"]},{"type":"object","properties":{"kind":{"type":"string","enum":["nothing_to_compare"],"description":"The bundle holds no app and no priced monthly service.","example":"nothing_to_compare"}},"required":["kind"]},{"type":"object","properties":{"kind":{"type":"string","enum":["one_time"],"description":"A one-time price, which is not compared with recurring prices.","example":"one_time"},"oneTimeServicesCents":{"type":"integer","description":"What the one-time services in the bundle cost on their own, in US cents, which no period includes.","example":50000}},"required":["kind","oneTimeServicesCents"]},{"type":"object","properties":{"kind":{"type":"string","enum":["unlimited_sites"],"description":"Unlimited sites, so there is no fixed sum to compare.","example":"unlimited_sites"},"perSiteCents":{"type":"integer","description":"What the apps cost on their own for one site over the period, in US cents.","example":1900},"months":{"type":"integer","description":"How many months the compared period spans: 12 for a yearly price, else 1.","example":1},"oneTimeServicesCents":{"type":"integer","description":"What the one-time services in the bundle cost on their own, in US cents, which no period includes.","example":50000}},"required":["kind","perSiteCents","months","oneTimeServicesCents"]},{"type":"object","properties":{"kind":{"type":"string","enum":["fixed_sites"],"description":"The price against the apps at the site limit plus the monthly services.","example":"fixed_sites"},"sites":{"type":"integer","description":"The site limit the comparison uses.","example":3},"months":{"type":"integer","description":"How many months the compared period spans: 12 for a yearly price, else 1.","example":1},"appsCents":{"type":"integer","description":"What the apps cost on their own at the site limit over the period, in US cents.","example":5700},"servicesCents":{"type":"integer","description":"What the monthly services cost on their own over the period, in US cents.","example":0},"separatelyCents":{"type":"integer","description":"`appsCents` plus `servicesCents`.","example":5700},"savingCents":{"type":["integer","null"],"description":"`separatelyCents` minus the bundle price, in US cents; 0 or less when the bundle is not cheaper. Null while the bundle has no price.","example":2800},"savingPercent":{"type":"integer","description":"The saving as a whole percent of `separatelyCents`; 0 when there is none.","example":49},"oneTimeServicesCents":{"type":"integer","description":"What the one-time services in the bundle cost on their own, in US cents, which no period includes.","example":50000}},"required":["kind","sites","months","appsCents","servicesCents","separatelyCents","savingCents","savingPercent","oneTimeServicesCents"]}],"description":"How the bundle price compares with buying its apps and services separately.","example":{"kind":"fixed_sites","sites":3,"months":1,"appsCents":5700,"servicesCents":0,"separatelyCents":5700,"savingCents":2800,"savingPercent":49,"oneTimeServicesCents":50000}},"StoreBundleLink":{"oneOf":[{"type":"object","properties":{"offer":{"type":"string","enum":["available"],"description":"The link works and the bundle can be bought.","example":"available"},"bundle":{"$ref":"#/components/schemas/StoreBundle"}},"required":["offer","bundle"]},{"type":"object","properties":{"offer":{"type":"string","enum":["ended"],"description":"The link no longer offers anything.","example":"ended"},"reason":{"type":"string","enum":["revoked","used_up","not_for_sale"],"description":"Why: `revoked` by the developer, `used_up` when every purchase the link allowed was made, or `not_for_sale` when the bundle is Paused or Retired or cannot be sold right now.","example":"revoked"}},"required":["offer","reason"]}],"description":"What a bundle link offers right now."}},"parameters":{}},"paths":{"/system/health":{"get":{"operationId":"getSystemHealth","tags":["System"],"summary":"Check readiness","description":"Reports whether the API is ready to serve requests. Wire it to uptime monitors and deployment health checks.\n\n#### How it works\n\nA 503 means the API is temporarily not ready — retry with backoff rather than treating it as permanent.","security":[],"responses":{"200":{"description":"The API is ready to serve requests.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["success"],"description":"Always `success`: the API is ready to serve requests.","example":"success"}},"required":["status"]}}}},"503":{"description":"The API is temporarily not ready; retry with backoff.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["error"],"description":"Always `error`: the API is temporarily not ready. No further detail is exposed to the caller.","example":"error"}},"required":["status"]}}}}}}},"/teams":{"get":{"operationId":"listTeams","tags":["Teams"],"summary":"List the token’s teams","description":"Returns every team this credential may access. Start here: every other operation needs a `teamId`.\n\n#### How it works\n\nA team API token returns its one team. An OAuth token returns the teams selected when the session was authorized.\n\n#### Required permissions\n\n- None beyond a valid token; the response contains only the token’s bound team","security":[{"QintoAccessToken":[]}],"responses":{"200":{"description":"The teams this token may access.","content":{"application/json":{"schema":{"type":"object","properties":{"teams":{"type":"array","items":{"$ref":"#/components/schemas/Team"},"description":"The teams authorized for this credential."}},"required":["teams"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/members":{"get":{"operationId":"listTeamMembers","tags":["Team members"],"summary":"List team members","description":"Returns every Qinto user who belongs to the team. Use it to render a team roster or to resolve a person to the `userId` other tooling (audit logs, support requests) refers to.\n\n#### How it works\n\nThe list is returned in full — it is not paginated. A member’s name fields are null until they complete their profile.\n\n#### Required permissions\n\n- `team:read` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"}],"responses":{"200":{"description":"The team’s full member list.","content":{"application/json":{"schema":{"type":"object","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/TeamMember"},"description":"Every member of the team; a team always has at least its owner."}},"required":["members"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/hosts":{"get":{"operationId":"listHosts","tags":["Hosts"],"summary":"List hosts","description":"Returns every Cloudflare account connected to the team as a host. Use it to discover the `hostId` values the get, update and delete operations address, or to check whether an account is already connected before creating a duplicate.\n\n#### How it works\n\nThe list is returned in full — it is not paginated. API tokens are never included.\n\n#### Required permissions\n\n- `domain:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"}],"responses":{"200":{"description":"Every host connected to the team.","content":{"application/json":{"schema":{"type":"object","properties":{"hosts":{"type":"array","items":{"$ref":"#/components/schemas/Host"},"description":"Every host connected to the team; empty when none are connected yet."}},"required":["hosts"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"post":{"operationId":"createHost","tags":["Hosts"],"summary":"Create a host","description":"Connects a Cloudflare account to the team as a host. Use it once per Cloudflare account the team should manage domains under; the returned `hostId` is what subsequent host operations reference.\n\n#### How it works\n\nThe API token is verified against Cloudflare before anything is stored: a token that is inactive or cannot read the account fails with `invalid_credentials` and creates nothing. Verification does not prove every permission later host operations need. The token is write-only — no read operation returns it. The host also needs a zone: an account with exactly one has it chosen automatically, otherwise `zoneRequired` lists the candidates and the zone operation records the choice, which adding sites waits on. A `wfpSync` that reports not pushed can be retried with the sync operation.\n\n#### Required permissions\n\n- `domain:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"}],"requestBody":{"required":true,"description":"Connection details for the Cloudflare account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateHostRequest"}}}},"responses":{"201":{"description":"The host was verified and created; the response echoes its stored representation.","content":{"application/json":{"schema":{"type":"object","properties":{"host":{"$ref":"#/components/schemas/Host"},"wfpSync":{"type":["object","null"],"properties":{"pushed":{"type":"boolean","description":"Whether the account’s control-token registry reached its dispatcher.","example":true},"reason":{"type":"string","enum":["configuration_failed","shared_dispatcher_missing","dispatcher_missing","push_failed","bundles_missing","zone_required","custom_hostnames_disabled","fallback_origin_failed","qinto_url_failed","subdomain_failed","namespace_failed","dispatcher_failed","route_failed","registry_busy"],"description":"Why provisioning stopped: `zone_required` means no zone is chosen yet, so nothing was provisioned; `custom_hostnames_disabled` means the zone’s plan does not include Cloudflare for SaaS; `fallback_origin_failed`, `subdomain_failed`, `namespace_failed`, `dispatcher_failed`, and `route_failed` name the account-provisioning step that errored; `qinto_url_failed` names a step that only runs for Qinto-managed hosting, so it never appears here; `dispatcher_missing` and `push_failed` mean the token-registry push itself did not land; `bundles_missing` means the Blotout platform deployment is missing its released worker bundles; `registry_busy` means another rewrite of the account’s control-token registry — a token rotation, its cleanup, or another deploy — was running, so the dispatcher deploy stepped aside. Every step is idempotent, so syncing again retries the whole provisioning. `configuration_failed` requires checking account credentials and hosting settings; `shared_dispatcher_missing` means EdgeTag removed shared hosting, which Qinto will not recreate. Contact the account operator. Absent when `pushed` is true.","example":"dispatcher_failed"}},"required":["pushed"],"description":"Outcome of pushing the account’s Workers-for-Platforms control-token registry to its dispatcher. Null when WFP was not enabled for the host."},"zoneRequired":{"type":["array","null"],"items":{"type":"string"},"description":"Zones the host’s Cloudflare account can reach, present only when Qinto could not pick one for you — the account has none, or more than one. Choose one with the zone operation; provisioning finishes then. Null when a zone is already set.","example":["agency.example.com","agency-eu.example.com"]}},"required":["host","wfpSync","zoneRequired"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"422":{"description":"`invalid_credentials` — The host details failed verification: Cloudflare rejected the account id and API token, the name duplicates an existing host in the team, or (on update) no token is stored to verify with. `message` states the exact reason.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_credentials"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_credentials"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/hosts/{hostId}":{"get":{"operationId":"getHost","tags":["Hosts"],"summary":"Get a host","description":"Returns one host by id. Use it to refresh a single host’s details instead of re-listing all of them, for example after an update or when following a stored `hostId` reference.\n\n#### How it works\n\nThe API token is never included. An unknown id answers `not_found`.\n\n#### Required permissions\n\n- `domain:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the host, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the host, as returned by the create and list operations.","name":"hostId","in":"path"}],"responses":{"200":{"description":"The addressed host.","content":{"application/json":{"schema":{"type":"object","properties":{"host":{"$ref":"#/components/schemas/Host"}},"required":["host"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"put":{"operationId":"updateHost","tags":["Hosts"],"summary":"Update a host","description":"Replaces a host’s editable fields — its name and its Cloudflare API token — in one call. Send the full desired state, not a diff. A host’s Cloudflare account is fixed when the host is created: to manage a different account, create a separate host for it. The original host can be deleted once no sites reference it.\n\n#### How it works\n\nThe API token alone is optional: omit it (or send an empty string) to keep the stored one. A replacement token is verified against Cloudflare before anything is written — a rejected token fails with `invalid_credentials` and leaves the stored one unchanged. Any property other than `name` and `apiToken` is rejected as `invalid_body`.\n\n#### Required permissions\n\n- `team:write` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the host, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the host, as returned by the create and list operations.","name":"hostId","in":"path"}],"requestBody":{"required":true,"description":"The host’s full replacement state; only the API token may be omitted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateHostRequest"}}}},"responses":{"200":{"description":"The host was updated; the response echoes its stored representation.","content":{"application/json":{"schema":{"type":"object","properties":{"host":{"$ref":"#/components/schemas/Host"}},"required":["host"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"422":{"description":"`invalid_credentials` — The host details failed verification: Cloudflare rejected the account id and API token, the name duplicates an existing host in the team, or (on update) no token is stored to verify with. `message` states the exact reason.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_credentials"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_credentials"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"delete":{"operationId":"deleteHost","tags":["Hosts"],"summary":"Delete a host","description":"Permanently disconnects the Cloudflare account from the team; the `hostId` becomes invalid for every other operation.\n\n#### How it works\n\nThe delete is refused with `in_use` while other team resources still reference the host — remove those first; nothing is deleted partially. It is refused with `wfp_revoke_failed` when the host’s access cannot be withdrawn from its Cloudflare account, which is safe to retry. Deleting only severs the Blotout platform’s connection: the Cloudflare account itself is untouched.\n\n#### Required permissions\n\n- `team:write` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the host, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the host, as returned by the create and list operations.","name":"hostId","in":"path"}],"responses":{"200":{"description":"The host was disconnected; its id is no longer valid.","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true],"description":"Always true: the host no longer exists. Its id becomes invalid for all other operations.","example":true}},"required":["deleted"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`in_use` — The resource is still referenced by other resources and cannot be deleted; remove the dependents first. `wfp_revoke_failed` — The host’s WFP control token could not be revoked from its account’s dispatcher, so the operation was refused; retry once Cloudflare is reachable. `wfp_route_cleanup_failed` — The dispatcher route on the host’s Cloudflare zone could not be removed, so the operation was refused rather than leave the zone routing all of its traffic to Qinto; retry once Cloudflare is reachable. `wfp_registry_restore_failed` — The operation was refused, but the host’s control token had already been withdrawn from its account’s dispatcher and could not be put back, so that dispatcher cannot register new sites until the host is synced.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["in_use","wfp_revoke_failed","wfp_route_cleanup_failed","wfp_registry_restore_failed"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"in_use"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/hosts/{hostId}/wfp-sync":{"post":{"operationId":"syncHostWfp","tags":["Hosts"],"summary":"Sync the WFP account","description":"Finishes preparing the host’s Cloudflare account for Workers-for-Platforms hosting. Call it to retry a create or a zone change that reported a not-pushed `wfpSync` outcome.\n\n#### How it works\n\nEvery step is idempotent, so the call is safe to repeat until it succeeds. A host without WFP enabled answers `not_found`.\n\n#### Required permissions\n\n- `team:write` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the host, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the host, as returned by the create and list operations.","name":"hostId","in":"path"}],"responses":{"200":{"description":"The sync was attempted; the outcome reports whether it landed.","content":{"application/json":{"schema":{"type":"object","properties":{"wfpSync":{"type":"object","properties":{"pushed":{"type":"boolean","description":"Whether the account’s control-token registry reached its dispatcher.","example":true},"reason":{"type":"string","enum":["configuration_failed","shared_dispatcher_missing","dispatcher_missing","push_failed","bundles_missing","zone_required","custom_hostnames_disabled","fallback_origin_failed","qinto_url_failed","subdomain_failed","namespace_failed","dispatcher_failed","route_failed","registry_busy"],"description":"Why provisioning stopped: `zone_required` means no zone is chosen yet, so nothing was provisioned; `custom_hostnames_disabled` means the zone’s plan does not include Cloudflare for SaaS; `fallback_origin_failed`, `subdomain_failed`, `namespace_failed`, `dispatcher_failed`, and `route_failed` name the account-provisioning step that errored; `qinto_url_failed` names a step that only runs for Qinto-managed hosting, so it never appears here; `dispatcher_missing` and `push_failed` mean the token-registry push itself did not land; `bundles_missing` means the Blotout platform deployment is missing its released worker bundles; `registry_busy` means another rewrite of the account’s control-token registry — a token rotation, its cleanup, or another deploy — was running, so the dispatcher deploy stepped aside. Every step is idempotent, so syncing again retries the whole provisioning. `configuration_failed` requires checking account credentials and hosting settings; `shared_dispatcher_missing` means EdgeTag removed shared hosting, which Qinto will not recreate. Contact the account operator. Absent when `pushed` is true.","example":"dispatcher_failed"}},"required":["pushed"],"description":"Outcome of pushing the account’s Workers-for-Platforms control-token registry to its dispatcher."}},"required":["wfpSync"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/hosts/{hostId}/zone":{"post":{"operationId":"setHostZone","tags":["Hosts"],"summary":"Set the host zone","description":"Records which Cloudflare zone a host serves customer traffic from. Call it when a create or update returned a `zoneRequired` list, choosing one of its names.\n\n#### How it works\n\nThe zone must exist in the host’s Cloudflare account, otherwise the request fails with `invalid_credentials` and nothing is written. Once recorded, customers point their CNAME records at `<subdomain>.customers.<zoneDomain>`. The zone cannot be changed once a site references the host: that attempt fails with `in_use`. A `wfp_route_cleanup_failed` leaves the zone as it was and is safe to retry; a `wfpSync` that reports not pushed can be retried with the sync operation.\n\n#### Required permissions\n\n- `team:write` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the host, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the host, as returned by the create and list operations.","name":"hostId","in":"path"}],"requestBody":{"required":true,"description":"The zone the host serves its customers from.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetHostZoneRequest"}}}},"responses":{"200":{"description":"The zone was recorded; the response echoes the host and any WFP provisioning outcome.","content":{"application/json":{"schema":{"type":"object","properties":{"host":{"$ref":"#/components/schemas/Host"},"wfpSync":{"type":["object","null"],"properties":{"pushed":{"type":"boolean","description":"Whether the account’s control-token registry reached its dispatcher.","example":true},"reason":{"type":"string","enum":["configuration_failed","shared_dispatcher_missing","dispatcher_missing","push_failed","bundles_missing","zone_required","custom_hostnames_disabled","fallback_origin_failed","qinto_url_failed","subdomain_failed","namespace_failed","dispatcher_failed","route_failed","registry_busy"],"description":"Why provisioning stopped: `zone_required` means no zone is chosen yet, so nothing was provisioned; `custom_hostnames_disabled` means the zone’s plan does not include Cloudflare for SaaS; `fallback_origin_failed`, `subdomain_failed`, `namespace_failed`, `dispatcher_failed`, and `route_failed` name the account-provisioning step that errored; `qinto_url_failed` names a step that only runs for Qinto-managed hosting, so it never appears here; `dispatcher_missing` and `push_failed` mean the token-registry push itself did not land; `bundles_missing` means the Blotout platform deployment is missing its released worker bundles; `registry_busy` means another rewrite of the account’s control-token registry — a token rotation, its cleanup, or another deploy — was running, so the dispatcher deploy stepped aside. Every step is idempotent, so syncing again retries the whole provisioning. `configuration_failed` requires checking account credentials and hosting settings; `shared_dispatcher_missing` means EdgeTag removed shared hosting, which Qinto will not recreate. Contact the account operator. Absent when `pushed` is true.","example":"dispatcher_failed"}},"required":["pushed"],"description":"Outcome of pushing the account’s Workers-for-Platforms control-token registry to its dispatcher. Null when the host does not participate in Workers for Platforms."}},"required":["host","wfpSync"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`in_use` — The resource is still referenced by other resources and cannot be deleted; remove the dependents first. `wfp_route_cleanup_failed` — The dispatcher route on the host’s Cloudflare zone could not be removed, so the operation was refused rather than leave the zone routing all of its traffic to Qinto; retry once Cloudflare is reachable.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["in_use","wfp_route_cleanup_failed"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"in_use"}},"required":["error"]}}}},"422":{"description":"`invalid_credentials` — The host details failed verification: Cloudflare rejected the account id and API token, the name duplicates an existing host in the team, or (on update) no token is stored to verify with. `message` states the exact reason.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_credentials"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_credentials"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains":{"post":{"operationId":"createSite","tags":["Sites"],"summary":"Create a site","description":"Registers a customer domain as a site and provisions the hostname Qinto will serve it on. This is the first step of onboarding; the returned `domainId` is what every other site operation references.\n\n#### How it works\n\nThe site is created `pending` and serves nothing until it is deployed. Its hostname is `<subdomain>.<rootDomain>`, with a random subdomain when none is given. `jurisdiction`, `locationHint`, `subdomain` and the host are fixed at creation and cannot be changed afterwards — create a new site to change them. Hostnames stay reserved after a site is deleted, so `already_exists` can name a site you can no longer see. Managed hosting needs no `hostId`; self-hosting requires one whose zone is already chosen.\n\n#### Required permissions\n\n- `domain:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"}],"requestBody":{"required":true,"description":"The customer domain to serve, and where to host it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSiteRequest"}}}},"responses":{"201":{"description":"The site was created and its hostname provisioned.","content":{"application/json":{"schema":{"type":"object","properties":{"site":{"$ref":"#/components/schemas/Site"}},"required":["site"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed. `invalid_site` — The site details were rejected before anything was created — a malformed root domain, a reserved or malformed subdomain, an unknown jurisdiction or location, or a name that is too long. `message` states which.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body","invalid_site"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`already_exists` — A site already occupies this hostname. Deleted sites keep their hostname reserved, so this can name a site that is no longer visible. `message` says whether it is one of yours.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["already_exists"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"already_exists"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"422":{"description":"`host_not_ready` — The site’s host is not ready to serve it — no Cloudflare zone chosen, no stored API token, a token scoped to the wrong zone, a conflicting DNS record, or a dispatcher that refused the request. `message` names the fix.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["host_not_ready"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"host_not_ready"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"429":{"description":"`rate_limited` — Too many requests for this API token or site in a short window; wait a minute and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"rate_limited"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}},"502":{"description":"`upstream_unavailable` — A provider Qinto depends on (Cloudflare for the DNS records, or the email service) could not be reached or refused the request. Delivery is unconfirmed rather than ruled out — a lost response can follow an accepted send — so retry with the same `submissionId`, which de-duplicates an identical retry at the provider.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["upstream_unavailable"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"upstream_unavailable"}},"required":["error"]}}}}}},"get":{"operationId":"listSites","tags":["Sites"],"summary":"List sites","description":"Lists the team’s sites. Use it to find a site’s `domainId`, or to check whether a team has been onboarded yet.\n\n#### How it works\n\nOnly sites covered by this token’s all-domain or selected-domain read policy are returned. An empty list means the team has no sites or none are covered. Deleted sites are never listed.\n\n#### Required permissions\n\n- `team:read` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"}],"responses":{"200":{"description":"The sites this token may read in the team.","content":{"application/json":{"schema":{"type":"object","properties":{"sites":{"type":"array","items":{"$ref":"#/components/schemas/Site"},"description":"Every site in the team the caller may read; empty when there are none."}},"required":["sites"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}":{"get":{"operationId":"getSite","tags":["Sites"],"summary":"Get a site","description":"Returns one site’s current state and the Qinto release it runs next to the newest one available. Poll it to watch a site move from `pending` to `active`, or to read where it is delivered from.\n\n#### How it works\n\nA deleted site is not returned; its id answers `not_found` even though the hostname stays reserved.\n\n#### Required permissions\n\n- `domain:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the create and list operations.","name":"domainId","in":"path"}],"responses":{"200":{"description":"The site’s current state.","content":{"application/json":{"schema":{"type":"object","properties":{"site":{"$ref":"#/components/schemas/SiteDetail"}},"required":["site"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"patch":{"operationId":"updateSite","tags":["Sites"],"summary":"Rename a site","description":"Changes the display name the site is listed under on the Blotout platform. Its hostname and every other setting stay as they are.\n\n#### How it works\n\nNull or blank lists the site under its root domain again. Sending the name the site already has changes nothing.\n\n#### Required permissions\n\n- `domain:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the create and list operations.","name":"domainId","in":"path"}],"requestBody":{"required":true,"description":"The new name.","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":["string","null"],"maxLength":80,"description":"New display name, at most 80 characters. Null or blank lists the site under its root domain again.","example":"Storefront"}},"required":["name"],"additionalProperties":false,"description":"The site’s new display name."}}}},"responses":{"200":{"description":"The renamed site.","content":{"application/json":{"schema":{"type":"object","properties":{"site":{"$ref":"#/components/schemas/Site"}},"required":["site"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed. `invalid_site` — The site details were rejected before anything was created — a malformed root domain, a reserved or malformed subdomain, an unknown jurisdiction or location, or a name that is too long. `message` states which.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body","invalid_site"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"delete":{"operationId":"deleteSite","tags":["Sites"],"summary":"Delete a site","description":"Deletes a site. It leaves the team at once and stops serving once the change reaches it.\n\n#### How it works\n\nThe site leaves the team as soon as the call succeeds, but it keeps serving until the change reaches it. `edgeSettled` reports whether that has happened: false means it is still serving and it retries on its own, so no action is needed — but do not read the response as proof it has stopped. Its resources are kept for 14 days and torn down after that. The site’s hostname stays reserved permanently, so it cannot be re-created at the same address. To guard against deleting the wrong site, `confirmation` must equal the site’s hostname, compared without regard to case or surrounding spaces.\n\n#### Required permissions\n\n- `domain:delete` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the create and list operations.","name":"domainId","in":"path"}],"requestBody":{"required":true,"description":"Confirmation that the right site is being deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteSiteRequest"}}}},"responses":{"200":{"description":"The site was deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true],"description":"Always true: the site has left the team.","example":true},"edgeSettled":{"type":"boolean","description":"Whether the site’s worker already knows it is deleted. False means it is still being told; no action is needed.","example":true}},"required":["deleted","edgeSettled"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`storage_linked` — The site is part of a storage link configuration, or its unlink has not reached every worker yet, so deleting it would leave another site bound to storage that no longer exists. Remove it from the configuration and wait for the sync to settle, then retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["storage_linked"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"storage_linked"}},"required":["error"]}}}},"422":{"description":"`invalid_confirmation` — The typed confirmation did not match the site’s hostname, so nothing was deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_confirmation"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_confirmation"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/dns":{"get":{"operationId":"getSiteDns","tags":["Sites"],"summary":"Get DNS records","description":"Returns the DNS records a customer must publish for a site, and whether they have taken effect. This is what to poll while waiting for a domain to verify.\n\n#### How it works\n\nThis operation only reads, so it is safe to call as often as you like. Use `POST /dns/check` to force a refresh after publishing records. A site Qinto attaches itself needs no records and reports `required: false`. When the lookup cannot run the response is still 200 with `checked: false`; read `failureKind` — `host_not_ready` and `not_configured` need a fix before retrying, anything else is worth retrying as-is.\n\n#### Required permissions\n\n- `domain:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the create and list operations.","name":"domainId","in":"path"}],"responses":{"200":{"description":"The site’s DNS records and verification state, including a state that could not be determined.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteDns"}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/dns/check":{"post":{"operationId":"checkSiteDns","tags":["Sites"],"summary":"Re-check DNS","description":"Re-checks a site’s DNS and returns the result. Call it once after publishing the records; use the read operation to poll.\n\n#### How it works\n\nWhen a site needs DNS records, this refreshes its hostname at the provider and re-creates it if it went missing; a site Qinto attaches itself needs no records and reports `required: false`. It is safe to repeat — poll with `GET /dns` instead. The response is the same shape as the read, including a `checked: false` result when the refresh could not run.\n\n#### Required permissions\n\n- `domain:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the create and list operations.","name":"domainId","in":"path"}],"responses":{"200":{"description":"The site’s DNS records and verification state, including a state that could not be determined.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteDns"}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/dns/share":{"post":{"operationId":"shareDnsInstructions","tags":["Sites"],"summary":"Share DNS instructions","description":"Emails a site’s outstanding DNS records to the people who administer its domain. Use it when whoever is setting the site up cannot edit DNS themselves.\n\n#### How it works\n\nRecipients always get the current records, and the email names the API token that shared them. Recipients are lowercased and de-duplicated before sending, and `sent` reports how many distinct addresses were mailed. A site served on a Qinto URL needs no DNS changes and returns `no_dns_records`. Sends are rate limited per API token and per site; exceeding either returns `rate_limited` and delivers nothing.\n\n#### Required permissions\n\n- `domain:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the create and list operations.","name":"domainId","in":"path"}],"requestBody":{"required":true,"description":"Who to send the instructions to, and the id identifying this send for safe retries.","content":{"application/json":{"schema":{"type":"object","properties":{"emails":{"type":"array","items":{"type":"string","format":"email","description":"One recipient address.","example":"dns-admin@example.com"},"minItems":1,"maxItems":10,"description":"Addresses to send the instructions to, between 1 and 10. Duplicates and case variants are collapsed before sending.","example":["dns-admin@example.com","ops@example.com"]},"submissionId":{"type":"string","format":"uuid","description":"Caller-generated UUID identifying this send. Reuse the same value to retry safely within 24 hours, provided the recipients, the site’s current DNS records and the sharing user are unchanged; anything else is treated as a new send and delivers a second email. Generate a new value to deliberately send again.","example":"7c9e6679-7425-40de-944b-e07fc1f90ae7"}},"required":["emails","submissionId"]}}}},"responses":{"200":{"description":"The instructions were sent; the response reports how many distinct addresses were mailed.","content":{"application/json":{"schema":{"type":"object","properties":{"sent":{"type":"number","description":"Number of distinct addresses the instructions were sent to, after duplicates were collapsed.","example":2}},"required":["sent"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`no_dns_records` — The site needs no DNS changes, so there are no instructions to share; it is served on a Qinto URL or its records are already in place.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["no_dns_records"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"no_dns_records"}},"required":["error"]}}}},"422":{"description":"`host_not_ready` — The site’s host is not ready to serve it — no Cloudflare zone chosen, no stored API token, a token scoped to the wrong zone, a conflicting DNS record, or a dispatcher that refused the request. `message` names the fix.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["host_not_ready"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"host_not_ready"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"429":{"description":"`rate_limited` — Too many requests for this API token or site in a short window; wait a minute and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"rate_limited"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}},"502":{"description":"`upstream_unavailable` — A provider Qinto depends on (Cloudflare for the DNS records, or the email service) could not be reached or refused the request. Delivery is unconfirmed rather than ruled out — a lost response can follow an accepted send — so retry with the same `submissionId`, which de-duplicates an identical retry at the provider.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["upstream_unavailable"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"upstream_unavailable"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/delivery":{"put":{"operationId":"setSiteDelivery","tags":["Sites"],"summary":"Set delivery mode","description":"Chooses whether a site is served from its own domain or from its Qinto URL. Use the Qinto URL to get started when the customer cannot edit DNS yet, and switch to their domain once the records are published.\n\n#### How it works\n\nAsking for the mode a site already has succeeds and changes nothing, so this is safe to repeat — and if an earlier change never took effect, repeating it tries again. `live` reports whether the site already serves the mode; false means it is still being applied and will retry on its own. The Qinto URL is only available before a site’s first deploy: once deployed, a site cannot be moved back to it. Switching an already-deployed site to its own domain requires verified DNS, so it cannot be taken offline by the change.\n\n#### Required permissions\n\n- `domain:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the create and list operations.","name":"domainId","in":"path"}],"requestBody":{"required":true,"description":"Where the site should be served from.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetSiteDeliveryRequest"}}}},"responses":{"200":{"description":"The delivery mode now stored for the site, and whether the edge already serves it.","content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["domain","development_url"],"description":"The delivery mode now stored for the site.","example":"domain"},"live":{"type":"boolean","description":"Whether the deployed worker already serves that mode. On a deployed site, false means it is still being applied and retries on its own; on a site that has never deployed, it stays false until you call deploy.","example":true}},"required":["mode","live"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed. `invalid_site` — The site details were rejected before anything was created — a malformed root domain, a reserved or malformed subdomain, an unknown jurisdiction or location, or a name that is too long. `message` states which.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body","invalid_site"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`already_verified` — The site’s DNS is verified, so it is served on its own domain and cannot be moved back to its Qinto URL. `unsupported_transition` — The requested delivery change is not supported for a site in this state. `message` states why; a deployed site cannot be moved back to its Qinto URL. `dns_not_verified` — The site’s DNS is not verified yet, so switching it to its own domain would take it offline. Publish the records, then retry. `dns_state_unknown` — The site’s DNS state could not be determined, so the delivery change was not applied. `message` states what failed; nothing was changed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["already_verified","unsupported_transition","dns_not_verified","dns_state_unknown"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"already_verified"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"422":{"description":"`host_not_ready` — The site’s host is not ready to serve it — no Cloudflare zone chosen, no stored API token, a token scoped to the wrong zone, a conflicting DNS record, or a dispatcher that refused the request. `message` names the fix.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["host_not_ready"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"host_not_ready"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"429":{"description":"`rate_limited` — Too many requests for this API token or site in a short window; wait a minute and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"rate_limited"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/deploy":{"post":{"operationId":"deploySite","tags":["Sites"],"summary":"Deploy a site","description":"Starts serving a site on its hostname, turning a `pending` site `active`. Until it runs, a site is registered but serves nothing.\n\n#### How it works\n\nThe request runs the deployment and does not return until it finishes, so expect it to take longer than the other operations. It is safe to retry: deploying an already-deployed site republishes it rather than creating a second one. Deploying is also how a site picks up later configuration changes. A site set to its Qinto URL is deployed without attaching the customer’s domain.\n\n#### Required permissions\n\n- `domain:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the create and list operations.","name":"domainId","in":"path"}],"responses":{"200":{"description":"The site was deployed and is now active.","content":{"application/json":{"schema":{"type":"object","properties":{"deploymentId":{"type":"string","description":"Id of the worker this deployment produced.","example":"shopexamplecom-3f2a9c81"},"version":{"type":"string","description":"Version of the Qinto worker the site now runs.","example":"1.4.0"}},"required":["deploymentId","version"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"402":{"description":"`no_payment_method` — The team pays by card and has no payment method on file, so nothing was deployed or installed. Add a card on the team’s Billing page, then retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["no_payment_method"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"no_payment_method"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`deploy_in_progress` — Another deployment for this site is already running. Wait for it to finish, then retry. `storage_link_blocked` — The site’s storage link holds this deployment: its parent has not published the link yet (the sync retries on its own), a linked resource could not be resolved on the parent, or the deploy would retire a resource a linked child still binds. `message` states which. `apps_updating` — An app worker on this site still runs an older app runtime or does not yet hold a saved value, so the site was not published. The sync finishes this on its own; retry in a few minutes. `message` states which. `sites_paused` — Blotout has paused this team’s sites, so nothing was deployed or installed. Every site of the team answers 410 until the pause ends, and uninstalls, switches and settings changes are still recorded. A payment does not end the pause; contact Blotout. `deploys_blocked` — Blotout has blocked this team’s deploys, so nothing was deployed or installed. The team’s live sites keep running, and uninstalls, switches and settings changes still roll out. A payment does not lift the block; contact Blotout.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["deploy_in_progress","storage_link_blocked","apps_updating","sites_paused","deploys_blocked"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"deploy_in_progress"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"422":{"description":"`host_not_ready` — The site’s host is not ready to serve it — no Cloudflare zone chosen, no stored API token, a token scoped to the wrong zone, a conflicting DNS record, or a dispatcher that refused the request. `message` names the fix.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["host_not_ready"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"host_not_ready"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}},"502":{"description":"`upstream_unavailable` — A provider Qinto depends on (Cloudflare for the DNS records, or the email service) could not be reached or refused the request. Delivery is unconfirmed rather than ruled out — a lost response can follow an accepted send — so retry with the same `submissionId`, which de-duplicates an identical retry at the provider.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["upstream_unavailable"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"upstream_unavailable"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/snippet":{"get":{"operationId":"getSiteSnippet","tags":["Sites"],"summary":"Get the install snippet","description":"Returns the script tag to install on the customer’s pages, and the host it loads from. This is the last step of onboarding.\n\n#### How it works\n\nThe snippet names the host currently serving the site, so a delivery change that has not taken effect yet still returns the previous host — check `deliveryLive` on the site if you need to know. A site that has never been deployed answers `not_deployed`. When `usingDevelopmentUrl` is true the site is on its Qinto URL, which works but gives no persistent visitor id.\n\n#### Required permissions\n\n- `domain:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the create and list operations.","name":"domainId","in":"path"}],"responses":{"200":{"description":"The snippet to install, and the host it loads from.","content":{"application/json":{"schema":{"type":"object","properties":{"host":{"type":"string","description":"Host the site is served from, and the one the snippet loads from.","example":"shop.example.com"},"usingDevelopmentUrl":{"type":"boolean","description":"Whether that host is the Qinto URL rather than the customer’s own domain, which means no persistent visitor id.","example":false},"snippet":{"type":"string","description":"The script tag to paste into every page’s `<head>`.","example":"<script>…</script>"}},"required":["host","usingDevelopmentUrl","snippet"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`not_deployed` — The site has never been deployed, so it has no host to describe yet. Deploy it, then retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_deployed"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_deployed"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/settings":{"get":{"operationId":"getSiteSettings","tags":["Sites"],"summary":"Get site settings","description":"Returns the site’s snippet global, visitor-recovery cookie, first-party cookie mode, consent mode, Global Privacy Control handling and automatic capture.\n\n#### Required permissions\n\n- `domain:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the create and list operations.","name":"domainId","in":"path"}],"responses":{"200":{"description":"The site’s current settings.","content":{"application/json":{"schema":{"type":"object","properties":{"settings":{"$ref":"#/components/schemas/SiteSettings"}},"required":["settings"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"patch":{"operationId":"updateSiteSettings","tags":["Sites"],"summary":"Update site settings","description":"Changes any of the site’s snippet global, visitor-recovery cookie, first-party cookie mode, consent mode, Global Privacy Control handling and automatic capture in one call, which the site applies with a single redeploy.\n\n#### How it works\n\nSettings left out keep their value, and a value the site already has changes nothing. An invalid value stores nothing. A new `tagGlobal` is stored only once the site has redeployed: when the redeploy fails the call answers `internal`, the other settings in the call are stored and retry on their own, and repeating the call is safe. `deployed` is false until the site serves every stored setting: deploy a site that has never deployed; a deployed one retries on its own.\n\n#### Required permissions\n\n- `domain:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the create and list operations.","name":"domainId","in":"path"}],"requestBody":{"required":true,"description":"The settings to change.","content":{"application/json":{"schema":{"type":"object","properties":{"tagGlobal":{"type":["string","null"],"maxLength":32,"description":"Window global for the snippet, at most 32 characters: a JavaScript identifier starting with a lowercase letter, `_` or `$`. Null, blank or `qinto` restores the default.","example":"acme"},"fallbackCookie":{"type":["string","null"],"maxLength":128,"description":"Name of the site’s own cookie to recover visitor ids from, at most 128 characters. Null or blank turns recovery off.","example":"_shopify_y"},"cookieSameSite":{"type":"string","enum":["strict","none"],"description":"SameSite mode of the first-party cookie Qinto recognizes returning visitors with. Allowed origins receive it only with `none`.","example":"strict"},"consent":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether each event goes only to the apps whose consent category the visitor allowed. Off sends every event to every app.","example":true}},"required":["enabled"],"description":"Consent mode."},"gpc":{"type":"boolean","description":"Whether a visitor whose browser sends Global Privacy Control is treated as opted out of marketing and sale of data.","example":true},"autoCapture":{"type":"object","properties":{"pageLoad":{"type":"boolean","description":"Whether Qinto records a page-load event without the customer instrumenting it.","example":false}},"required":["pageLoad"],"description":"Events Qinto captures without the customer instrumenting them."}},"additionalProperties":false,"description":"Any of the site’s settings. Settings left out keep their current value."}}}},"responses":{"200":{"description":"The settings now stored, and whether the site already serves them.","content":{"application/json":{"schema":{"type":"object","properties":{"settings":{"$ref":"#/components/schemas/SiteSettings"},"deployed":{"type":"boolean","description":"Whether the site already serves every setting stored for it. False on a site that has never deployed — call deploy — and false while a change has not reached the site yet, which retries on its own.","example":true}},"required":["settings","deployed"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed. `invalid_settings` — A window global or cookie name was rejected, and no setting was stored. `message` states which and why.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body","invalid_settings"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/bot-protection":{"get":{"operationId":"getSiteBotProtection","tags":["Sites"],"summary":"Get bot protection","description":"Returns the site’s Cloudflare bot-score floor, its optional country allow or block list, and whether it blocks verified bots.\n\n#### Required permissions\n\n- `domain:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the create and list operations.","name":"domainId","in":"path"}],"responses":{"200":{"description":"The site’s current bot-protection settings.","content":{"application/json":{"schema":{"type":"object","properties":{"minBotScore":{"type":"integer","description":"Minimum Cloudflare bot score (1–99) a request must meet to be treated as a human.","example":2},"countries":{"type":["object","null"],"properties":{"mode":{"type":"string","enum":["allow","block"],"description":"`allow` admits only the listed countries; `block` admits every country except those listed.","example":"block"},"list":{"type":"array","items":{"type":"string","minLength":1},"description":"ISO 3166-1 alpha-2 country codes, plus `EU` for the Union as a whole.","example":["CN","RU"]}},"required":["mode","list"],"description":"Country allow/block rule, or null when country filtering is off.","example":null},"blockVerifiedBots":{"type":"boolean","description":"Whether the site blocks verified bots, such as search engine crawlers and uptime monitors.","example":true}},"required":["minBotScore","countries","blockVerifiedBots"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"patch":{"operationId":"updateSiteBotProtection","tags":["Sites"],"summary":"Update bot protection","description":"Changes any of the site’s minimum bot score, country allow/block rule and verified-bot blocking in one call, which the site applies with a single redeploy. Send `countries: null` to clear country filtering.\n\n#### How it works\n\nSettings left out keep their value, and a value the site already has changes nothing. When `blockVerifiedBots` is false, verified bots skip the minimum bot score, but country rules still apply. `deployed` is false until the site serves every stored setting: deploy a site that has never deployed; a deployed one retries on its own.\n\n#### Required permissions\n\n- `domain:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the create and list operations.","name":"domainId","in":"path"}],"requestBody":{"required":true,"description":"The bot protection settings to change.","content":{"application/json":{"schema":{"type":"object","properties":{"minBotScore":{"type":"integer","minimum":1,"maximum":99,"description":"Replacement minimum Cloudflare bot score, from 1 through 99.","example":30},"countries":{"type":["object","null"],"properties":{"mode":{"type":"string","enum":["allow","block"],"description":"`allow` admits only the listed countries; `block` admits every country except those listed.","example":"block"},"list":{"type":"array","items":{"type":"string","minLength":1},"minItems":1,"description":"ISO 3166-1 alpha-2 country codes, plus `EU` for the Union as a whole. At least one.","example":["CN","RU"]}},"required":["mode","list"],"description":"Replacement country allow/block rule, or null to clear country filtering.","example":{"mode":"block","list":["CN","RU"]}},"blockVerifiedBots":{"type":"boolean","description":"`true` blocks verified bots; `false` lets them skip the minimum bot score.","example":false}},"additionalProperties":false,"description":"Any of `minBotScore`, `countries` and `blockVerifiedBots`. Settings left out keep their current value."}}}},"responses":{"200":{"description":"The settings now stored, and whether the site already serves them.","content":{"application/json":{"schema":{"type":"object","properties":{"minBotScore":{"type":"integer","description":"The minimum bot score now stored for the site.","example":30},"countries":{"type":["object","null"],"properties":{"mode":{"type":"string","enum":["allow","block"],"description":"`allow` admits only the listed countries; `block` admits every country except those listed.","example":"block"},"list":{"type":"array","items":{"type":"string","minLength":1},"description":"ISO 3166-1 alpha-2 country codes, plus `EU` for the Union as a whole.","example":["CN","RU"]}},"required":["mode","list"],"description":"The country rule now stored for the site, or null when country filtering is off.","example":null},"blockVerifiedBots":{"type":"boolean","description":"Whether the site now blocks verified bots.","example":true},"deployed":{"type":"boolean","description":"Whether the site already serves every setting stored for it. False on a site that has never deployed — call deploy — and false while a change has not reached the site yet, which retries on its own.","example":true}},"required":["minBotScore","countries","blockVerifiedBots","deployed"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed. `invalid_bot_protection` — The bot score or country rule was rejected. `message` states which.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body","invalid_bot_protection"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/origins":{"get":{"operationId":"getSiteOrigins","tags":["Sites"],"summary":"Get allowed origins","description":"Returns whether the site checks the origin of pages that use its snippet and call its apps, and the extra origins it allows besides its own root domain.\n\n#### Required permissions\n\n- `domain:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the create and list operations.","name":"domainId","in":"path"}],"responses":{"200":{"description":"The site’s current origin settings.","content":{"application/json":{"schema":{"type":"object","properties":{"originCheck":{"type":"boolean","description":"Whether only pages on the site’s root domain, its subdomains and `allowedOrigins` may use the snippet and call the site’s apps. Off lets any origin.","example":true},"allowedOrigins":{"type":"array","items":{"type":"string"},"description":"Extra `https://` origins whose pages may use the snippet and call the site’s apps while `originCheck` is on.","example":["https://shop.myshopify.com"]}},"required":["originCheck","allowedOrigins"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"patch":{"operationId":"updateSiteOrigins","tags":["Sites"],"summary":"Update allowed origins","description":"Turns the site’s origin check on or off, replaces the extra origins it allows, or both, with a single redeploy. List an origin such as a store’s myshopify.com address to let its pages use the snippet.\n\n#### How it works\n\nA field left out keeps its value, and the list is kept while the check is off. Origins are stored normalized and de-duplicated, and an invalid one stores nothing. `deployed` is false until the site serves every stored setting: deploy a site that has never deployed; a deployed one retries on its own.\n\n#### Required permissions\n\n- `domain:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the create and list operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the create and list operations.","name":"domainId","in":"path"}],"requestBody":{"required":true,"description":"The origin check, the origin list, or both.","content":{"application/json":{"schema":{"type":"object","properties":{"originCheck":{"type":"boolean","description":"Whether only pages on the site’s root domain, its subdomains and `allowedOrigins` may use the snippet and call the site’s apps. Off lets any origin.","example":true},"allowedOrigins":{"type":"array","items":{"type":"string"},"maxItems":20,"description":"Replacement list of `https://host` origins, up to 20, kept while the check is off. An empty list allows none beyond the root domain.","example":["https://shop.myshopify.com"]}},"additionalProperties":false,"description":"The origin check, the origin list, or both. A field left out keeps its current value."}}}},"responses":{"200":{"description":"The origin settings now stored, and whether the site already serves them.","content":{"application/json":{"schema":{"type":"object","properties":{"originCheck":{"type":"boolean","description":"Whether only pages on the site’s root domain, its subdomains and `allowedOrigins` may use the snippet and call the site’s apps. Off lets any origin.","example":true},"allowedOrigins":{"type":"array","items":{"type":"string"},"description":"Extra `https://` origins whose pages may use the snippet and call the site’s apps while `originCheck` is on.","example":["https://shop.myshopify.com"]},"deployed":{"type":"boolean","description":"Whether the site already serves every setting stored for it. False on a site that has never deployed — call deploy — and false while a change has not reached the site yet, which retries on its own.","example":true}},"required":["originCheck","allowedOrigins","deployed"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed. `invalid_origins` — An origin is not of the form `https://host`, or the list is too long, and nothing was stored. `message` states which.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body","invalid_origins"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/apps":{"get":{"operationId":"listSiteApps","tags":["Site apps"],"summary":"List installed apps","description":"Lists the apps installed on the site: what each one does, its selected and running versions, its switch, and its installs. Call it to discover the `appSlug` the other site-app operations address.\n\n#### Required permissions\n\n- `domain:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"}],"responses":{"200":{"description":"The site’s installed apps.","content":{"application/json":{"schema":{"type":"object","properties":{"apps":{"type":"array","items":{"$ref":"#/components/schemas/SiteApp"},"description":"The site’s installed apps, oldest install first."}},"required":["apps"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/included-apps":{"get":{"operationId":"listIncludedApps","tags":["Site apps"],"summary":"List a site’s included apps","description":"Lists one page of the apps a bundle the team bought covers on the site that the site does not run yet. Install one with the install operation at no charge beyond the bundle: it needs no charge approval.\n\n#### How it works\n\nEach app comes with the purchase that covers it, the version an install takes and that version’s consent category and legal links. An app that joined the bundle after the purchase is listed like any other; one the site runs, or one that was deleted, is not. Only a token with a user lists; a team API token is refused.\n\n#### Required permissions\n\n- `domain:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","description":"The `nextCursor.name` of the previous page.","example":"Facebook CAPI"},"required":false,"description":"The `nextCursor.name` of the previous page.","name":"cursorName","in":"query"},{"schema":{"type":"string","description":"The `nextCursor.id` of the previous page.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"required":false,"description":"The `nextCursor.id` of the previous page.","name":"cursorId","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"description":"Page size, 1–200 (default 50).","example":50},"required":false,"description":"Page size, 1–200 (default 50).","name":"limit","in":"query"}],"responses":{"200":{"description":"The included apps.","content":{"application/json":{"schema":{"type":"object","properties":{"apps":{"type":"array","items":{"$ref":"#/components/schemas/IncludedApp"},"description":"One page of the site’s included apps, A–Z by name."},"nextCursor":{"type":["object","null"],"properties":{"name":{"type":"string","description":"Name of the last listed app.","example":"Facebook CAPI"},"id":{"type":"string","description":"Id of the last listed app.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"}},"required":["name","id"],"description":"Pass it as `cursorName` and `cursorId` for the next page; null on the last page."}},"required":["apps","nextCursor"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/apps/{appSlug}":{"get":{"operationId":"getSiteApp","tags":["Site apps"],"summary":"Get an installed app","description":"Returns one installed app in full: versions and switch, the developer’s legal documents, the approved capabilities, the settings each install takes, and each install’s stored values and configuration state. Call it before configuring an install. Secret values are write-only and never part of this shape.\n\n#### Required permissions\n\n- `domain:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$","description":"Immutable slug of the app, as shown by the list operation.","example":"facebook-capi"},"required":true,"description":"Immutable slug of the app, as shown by the list operation.","name":"appSlug","in":"path"}],"responses":{"200":{"description":"The installed app.","content":{"application/json":{"schema":{"type":"object","properties":{"app":{"$ref":"#/components/schemas/SiteApp"},"variables":{"type":"array","items":{"$ref":"#/components/schemas/SiteVariableDefinition"},"description":"The settings each install takes, as the version the site is set to declares them, in manifest order."},"legal":{"type":"object","properties":{"termsUrl":{"type":"string","description":"The developer’s terms for this app.","example":"https://example.com/legal/terms"},"privacyUrl":{"type":"string","description":"The developer’s privacy policy for this app.","example":"https://example.com/legal/privacy"}},"required":["termsUrl","privacyUrl"],"description":"The developer’s legal documents, snapshotted with the installed version."},"capabilities":{"type":"object","properties":{"api":{"type":"array","items":{"type":"string"},"description":"The site-API scopes the app may call with its own token.","example":["track"]},"data":{"type":"array","items":{"type":"string"},"description":"The event-data buckets delivered to the app.","example":["customProperties"]}},"required":["api","data"],"description":"What the installed version may do and see, as approved at install."},"multipleInstalls":{"type":"boolean","description":"Whether the app supports more than one install per site.","example":true},"endpoints":{"type":"array","items":{"$ref":"#/components/schemas/SiteAppEndpoint"},"description":"The HTTP endpoints the deployed version declares; empty while no version is deployed. Each is served at `https://<site domain>/app/<slug><path>`, one URL for every install."},"capture":{"$ref":"#/components/schemas/SiteAppCapture"},"installs":{"type":"array","items":{"$ref":"#/components/schemas/SiteAppInstallDetail"},"description":"The app’s installs on this site, in install order."},"grants":{"type":"array","items":{"$ref":"#/components/schemas/SiteAppGrant"},"description":"The permission requests involving this app on this site."},"lifecycleDeliveries":{"type":"array","items":{"$ref":"#/components/schemas/SiteAppLifecycleDelivery"},"description":"Recent lifecycle-hook deliveries. Previous setting and secret snapshots are never returned."}},"required":["app","variables","legal","capabilities","multipleInstalls","endpoints","capture","installs","grants","lifecycleDeliveries"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"put":{"operationId":"installSiteApp","tags":["Site apps"],"summary":"Install an app","description":"Installs a ready app version on the site (creating its first install), or moves an already-installed app to the version. An app in the app store installs the same way, by its slug. Replaying with the current version is a no-op, so retries are safe.\n\n#### How it works\n\nA first install needs the caller to belong to the app’s organization, unless the app is in the app store; a later version move needs neither. With no version named, the newest version the site may run is installed. `approval_required`, `acknowledgement_required` and `dependencies_required` each name a flag to repeat the call with; `charge_approval_required` gives the `charge` for `approvedCharges`. Approving a charge needs `purchase_apps` on the credential and on its user. With `installDependencies` the missing apps install first, and if one fails nothing changes. A new install starts unconfigured; the site updates in the background.\n\n#### Required permissions\n\n- `domain:manage_domain_apps:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$","description":"Immutable slug of the app, as shown by the list operation.","example":"facebook-capi"},"required":true,"description":"Immutable slug of the app, as shown by the list operation.","name":"appSlug","in":"path"}],"requestBody":{"required":true,"description":"The version to install and the consent flags the operation may require.","content":{"application/json":{"schema":{"type":"object","properties":{"appVersionId":{"type":"string","format":"uuid","description":"The ready version to install or move to. Omit it, and `version`, to take the newest version the site may run: the newest approved version for a site that got the app from the app store, the newest published version otherwise.","example":"7d8e9f0a-1b2c-4d3e-9f4a-5b6c7d8e9f0a"},"version":{"type":"string","pattern":"^\\d+\\.\\d+\\.\\d+$","description":"The published version to install, named instead of `appVersionId`.","example":"1.4.1"},"label":{"type":"string","maxLength":100,"description":"Names the installation this call creates; left out or blank, it takes the app's name. Ignored by a version change.","example":"EU pixel"},"replaceRemoved":{"type":"boolean","description":"Discards a recent removal that could still be undone, so this call installs a new one instead; required to answer `restore_available`.","example":false},"installDependencies":{"type":"boolean","description":"Installs the apps the version needs that the site does not have yet, in the same step as the install or version move, and approves the plan’s private-function calls; required to answer `dependencies_required`.","example":true},"acknowledgeNecessaryDependencies":{"type":"array","items":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$"},"maxItems":50,"description":"The slugs of the apps this call installs as dependencies that run without visitor consent, each acknowledged; required when `acknowledgement_required` names one.","example":["consent-manager"]},"acceptCapabilities":{"type":"boolean","description":"Accepts the additional access a newer version requests, including any query params or cookies it newly captures; required when the change answers `approval_required`.","example":false},"acknowledgeNecessary":{"type":"boolean","description":"Records that this app runs without visitor consent; required when the call answers `acknowledgement_required`.","example":false},"approvedCharges":{"type":"object","additionalProperties":{"allOf":[{"$ref":"#/components/schemas/AppChargeApproval"},{"description":"The charge an install asks the team to approve, sent back in `approvedCharges`."}]},"description":"The charge a person was shown for each app that charges the team, by app slug: this app and every app the call installs with it, as `charge_approval_required` or the `dependencies_required` plan gave them. Approving it also accepts the developer’s terms. The call is refused with the current charge when an entry is missing, the amount went up or the free days went down since it was shown.","example":{"pixel-sync":{"upToCents":4900,"trialDays":14}}}},"description":"The version to install, with the name for the installation and the consent flags the operation may require."}}}},"responses":{"200":{"description":"What the call did.","content":{"application/json":{"schema":{"type":"object","properties":{"domainAppId":{"type":"string","description":"Id of the installation the call affected.","example":"6c5b4a39-2817-4d6e-9f0a-1b2c3d4e5f6a"},"action":{"type":"string","enum":["installed","version_changed","unchanged"],"description":"What the call did: a first install, a version move, or nothing (the version was already selected).","example":"installed"}},"required":["domainAppId","action"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"402":{"description":"`no_payment_method` — The team pays by card and has no payment method on file, so nothing was deployed or installed. Add a card on the team’s Billing page, then retry. `team_unpaid` — The team has an unpaid invoice, so it cannot install or enable an app that charges, buy a bundle, or add a site that charges. Nothing changed. Pay what is owed on the team’s Billing page, then retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["no_payment_method","team_unpaid"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"no_payment_method"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`version_not_ready` — The addressed version is still a draft; finalize the push, then retry. `install_changed` — The app installation was removed or replaced while this request was being prepared. Retry to check the current installation and its charges. `version_not_approved` — The site got the app from the app store, so it can run only approved versions. Name another version, or omit the version to get the newest approved one. `version_below_minimum` — Blotout set a minimum version for this app, and the named version is below it. Name the minimum version or a newer one, or omit the version to get the newest one the site may run. `version_not_offered` — Blotout has suspended this app, and the named version was published during the suspension. Name a version published before the suspension, or retry once the suspension is lifted. `cap_reached` — The operation would exceed a site-app capacity limit — either the installed-app count or the worker access-token environment. `message` names the exhausted capacity. `subscription_item_limit` — The team’s Stripe subscription holds the most lines it can, so no further app or bundle that charges can be added to it; `message` names the app or bundle. Nothing was installed or bought. Contact support. `quota_reached` — An object the version declares (a KV namespace, Durable Object class, Pipeline, Hyperdrive config, …) would push the site's host Cloudflare account past its per-account ceiling. `message` names the object type and the account's count; free objects or have the ceiling raised, then retry. `multiple_not_allowed` — The app allows only one install per site, or a version change would leave more installs than the target version allows. `message` states the conflict. `browser_budget` — A version's browser code, or a large value its browser code reads, would push the site's q.js past its size budget; shrink the value, or remove or shrink another app first. `restore_available` — This app was removed from the site recently and can still be brought back with its configuration and data. Call the restore operation to undo the removal, or repeat this call with `replaceRemoved` set to discard it and install a new one. `binding_conflict` — The target version binds a resource name that a version still running on this site binds to something else; `message` names both. Retrying cannot resolve it — the app must use a different binding name, or remove the binding in one version and re-add it in the next. `schema_incompatible` — The site has completed a contract D1 migration that the target app version does not include unchanged; select a schema-compatible version. `variable_retype` — The target version changes a variable’s kind or type while a version still running on this site declares the old shape; `message` names both. Retrying cannot resolve it — the app must use a different variable name, or remove the variable in one version and re-add it in the next. `linked` — The app’s storage is shared through a storage link: a child site binds this site’s objects, or this site binds a parent’s. `message` names the sites; change the link first, or make the change on the parent site. When a child site lacks an app the version needs, `message` names it; install it on that child first. `approval_required` — The target version requests more access than the installed one — API scopes, data buckets, or newly captured query params and cookies; `message` names the additions. Repeat the call with `acceptCapabilities` once a site manager accepts them. `acknowledgement_required` — The app, or an app it needs, declares `necessary` consent, so it runs without visitor consent; `message` names it. Repeat the call with `acknowledgeNecessary` for the app, or with the slug of the app it needs in `acknowledgeNecessaryDependencies`. `dependency_unavailable` — The app needs an app that cannot be installed on this site: it is not in the app store and you are not in its organization, it is suspended or deleted, or it has no version the site may run, or it was removed from this site recently and must be restored or installed on its own first. `message` names it. Nothing was installed. `registry_budget` — The change would grow the site's app configuration past the size the site worker can deploy. Remove an app or an install, or shorten install labels and geo filters, then retry. `message` states the refusal. `app_suspended` — Blotout has suspended this app, so nothing ran and nothing changed. The call works again once the suspension is lifted. `app_taken_down` — Blotout has taken this app down for good, so nothing changed. `message` states what the call cannot do. Do not retry. `purchase_ended` — The bundle purchase that covered the app ended while the install ran, so nothing was installed. Retry: the app then installs at its own price. `removal_pending` — A previous uninstall of this app is torn down as part of this call, and that teardown could not finish — because a deployment for the site is already running, or Cloudflare refused a delete. Nothing was left half-removed and the site's scheduled cleanup carries on, so retry. `sites_paused` — Blotout has paused this team’s sites, so nothing was deployed or installed. Every site of the team answers 410 until the pause ends, and uninstalls, switches and settings changes are still recorded. A payment does not end the pause; contact Blotout. `deploys_blocked` — Blotout has blocked this team’s deploys, so nothing was deployed or installed. The team’s live sites keep running, and uninstalls, switches and settings changes still roll out. A payment does not lift the block; contact Blotout. `charge_approval_required` — The call charges the team and did not approve that charge, or the charge went up, or its free days went down, after it was shown. `charge` holds the current charge and `message` states it. For an app, `appSlug` names the app the charge belongs to: once a person allowed to purchase apps accepts the charge and the developer’s terms, repeat the call with `{ \"<appSlug>\": <charge> }` in `approvedCharges`, keeping the other entries. For a bundle, repeat the call with `charge` as `approvedCharge`. Nothing was installed or bought. `dependencies_required` — The app needs other apps the site does not have yet; `plan` lists every app it needs, at any depth, and whether the site has it. Nothing was installed. Repeat the call with `installDependencies` to install the missing apps first, then the app, and approve the plan’s private-function calls.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["version_not_ready","install_changed","version_not_approved","version_below_minimum","version_not_offered","cap_reached","subscription_item_limit","quota_reached","multiple_not_allowed","browser_budget","restore_available","binding_conflict","schema_incompatible","variable_retype","linked","approval_required","acknowledgement_required","dependency_unavailable","registry_budget","app_suspended","app_taken_down","purchase_ended","removal_pending","sites_paused","deploys_blocked","charge_approval_required","dependencies_required"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"version_not_ready"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"plan":{"$ref":"#/components/schemas/AppDependencyPlan"},"charge":{"$ref":"#/components/schemas/AppChargeApproval"},"appSlug":{"type":"string","description":"With `charge_approval_required`: the app the charge belongs to.","example":"pixel-sync"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"patch":{"operationId":"updateSiteApp","tags":["Site apps"],"summary":"Update an installed app","description":"Flips the app-level kill switch with `{ enabled }`, or moves the app to another ready version with `{ appVersionId }`. A disabled app stops receiving everything while keeping its configuration.\n\n#### How it works\n\nA version move is the site’s own decision and needs no membership of the app’s organization. With `installDependencies` the apps the version needs install in the same step, and if one fails nothing changes. Enabling an app installed under a bundle purchase that has ended gives it the app’s current price: `charge_approval_required` carries `appSlug` and `charge`; repeat with them in `approvedCharges` once a person accepts it. Approving needs `purchase_apps` on the credential and on its user.\n\n#### Required permissions\n\n- `domain:manage_domain_apps:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$","description":"Immutable slug of the app, as shown by the list operation.","example":"facebook-capi"},"required":true,"description":"Immutable slug of the app, as shown by the list operation.","name":"appSlug","in":"path"}],"requestBody":{"required":true,"description":"The switch state, or the version to move to.","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"enabled":{"type":"boolean","description":"The replacement app-level switch state.","example":false},"approvedCharges":{"type":"object","additionalProperties":{"allOf":[{"$ref":"#/components/schemas/AppChargeApproval"},{"description":"The charge an install asks the team to approve, sent back in `approvedCharges`."}]},"description":"The app’s current price a person was shown, by app slug, when enabling an app installed under a bundle purchase that has ended; required when the call answers `charge_approval_required`.","example":{"pixel-sync":{"upToCents":4900,"trialDays":14}}}},"required":["enabled"],"additionalProperties":false},{"type":"object","properties":{"appVersionId":{"type":"string","format":"uuid","description":"The ready version to move the app to.","example":"7d8e9f0a-1b2c-4d3e-9f4a-5b6c7d8e9f0a"},"installDependencies":{"type":"boolean","description":"Installs the apps the version needs that the site does not have yet, in the same step as the install or version move, and approves the plan’s private-function calls; required to answer `dependencies_required`.","example":true},"acknowledgeNecessaryDependencies":{"type":"array","items":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$"},"maxItems":50,"description":"The slugs of the apps this call installs as dependencies that run without visitor consent, each acknowledged; required when `acknowledgement_required` names one.","example":["consent-manager"]},"acceptCapabilities":{"type":"boolean","description":"Accepts the additional access a newer version requests, including any query params or cookies it newly captures; required when the change answers `approval_required`.","example":false},"acknowledgeNecessary":{"type":"boolean","description":"Records that this app runs without visitor consent; required when the call answers `acknowledgement_required`.","example":false},"approvedCharges":{"type":"object","additionalProperties":{"allOf":[{"$ref":"#/components/schemas/AppChargeApproval"},{"description":"The charge an install asks the team to approve, sent back in `approvedCharges`."}]},"description":"The charge a person was shown for each app that charges the team, by app slug: this app and every app the call installs with it, as `charge_approval_required` or the `dependencies_required` plan gave them. Approving it also accepts the developer’s terms. The call is refused with the current charge when an entry is missing, the amount went up or the free days went down since it was shown.","example":{"pixel-sync":{"upToCents":4900,"trialDays":14}}}},"required":["appVersionId"],"additionalProperties":false}],"description":"Either `{ enabled }` to flip the kill switch, or `{ appVersionId }` to change the version (a developer act)."}}}},"responses":{"200":{"description":"The switch outcome, or what the version change did.","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"updated":{"type":"boolean","description":"Whether the switch actually changed.","example":true}},"required":["updated"]},{"type":"object","properties":{"domainAppId":{"type":"string","description":"Id of the installation the call affected.","example":"6c5b4a39-2817-4d6e-9f0a-1b2c3d4e5f6a"},"action":{"type":"string","enum":["installed","version_changed","unchanged"],"description":"What the call did: a first install, a version move, or nothing (the version was already selected).","example":"installed"}},"required":["domainAppId","action"]}]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"402":{"description":"`no_payment_method` — The team pays by card and has no payment method on file, so nothing was deployed or installed. Add a card on the team’s Billing page, then retry. `team_unpaid` — The team has an unpaid invoice, so it cannot install or enable an app that charges, buy a bundle, or add a site that charges. Nothing changed. Pay what is owed on the team’s Billing page, then retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["no_payment_method","team_unpaid"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"no_payment_method"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`version_not_ready` — The addressed version is still a draft; finalize the push, then retry. `version_not_approved` — The site got the app from the app store, so it can run only approved versions. Name another version, or omit the version to get the newest approved one. `version_below_minimum` — Blotout set a minimum version for this app, and the named version is below it. Name the minimum version or a newer one, or omit the version to get the newest one the site may run. `version_not_offered` — Blotout has suspended this app, and the named version was published during the suspension. Name a version published before the suspension, or retry once the suspension is lifted. `cap_reached` — The operation would exceed a site-app capacity limit — either the installed-app count or the worker access-token environment. `message` names the exhausted capacity. `subscription_item_limit` — The team’s Stripe subscription holds the most lines it can, so no further app or bundle that charges can be added to it; `message` names the app or bundle. Nothing was installed or bought. Contact support. `quota_reached` — An object the version declares (a KV namespace, Durable Object class, Pipeline, Hyperdrive config, …) would push the site's host Cloudflare account past its per-account ceiling. `message` names the object type and the account's count; free objects or have the ceiling raised, then retry. `multiple_not_allowed` — The app allows only one install per site, or a version change would leave more installs than the target version allows. `message` states the conflict. `browser_budget` — A version's browser code, or a large value its browser code reads, would push the site's q.js past its size budget; shrink the value, or remove or shrink another app first. `removal_pending` — A previous uninstall of this app is torn down as part of this call, and that teardown could not finish — because a deployment for the site is already running, or Cloudflare refused a delete. Nothing was left half-removed and the site's scheduled cleanup carries on, so retry. `install_changed` — The app installation was removed or replaced while this request was being prepared. Retry to check the current installation and its charges. `app_suspended` — Blotout has suspended this app, so nothing ran and nothing changed. The call works again once the suspension is lifted. `app_taken_down` — Blotout has taken this app down for good, so nothing changed. `message` states what the call cannot do. Do not retry. `binding_conflict` — The target version binds a resource name that a version still running on this site binds to something else; `message` names both. Retrying cannot resolve it — the app must use a different binding name, or remove the binding in one version and re-add it in the next. `schema_incompatible` — The site has completed a contract D1 migration that the target app version does not include unchanged; select a schema-compatible version. `variable_retype` — The target version changes a variable’s kind or type while a version still running on this site declares the old shape; `message` names both. Retrying cannot resolve it — the app must use a different variable name, or remove the variable in one version and re-add it in the next. `linked` — The app’s storage is shared through a storage link: a child site binds this site’s objects, or this site binds a parent’s. `message` names the sites; change the link first, or make the change on the parent site. When a child site lacks an app the version needs, `message` names it; install it on that child first. `approval_required` — The target version requests more access than the installed one — API scopes, data buckets, or newly captured query params and cookies; `message` names the additions. Repeat the call with `acceptCapabilities` once a site manager accepts them. `acknowledgement_required` — The app, or an app it needs, declares `necessary` consent, so it runs without visitor consent; `message` names it. Repeat the call with `acknowledgeNecessary` for the app, or with the slug of the app it needs in `acknowledgeNecessaryDependencies`. `charge_approval_required` — The call charges the team and did not approve that charge, or the charge went up, or its free days went down, after it was shown. `charge` holds the current charge and `message` states it. For an app, `appSlug` names the app the charge belongs to: once a person allowed to purchase apps accepts the charge and the developer’s terms, repeat the call with `{ \"<appSlug>\": <charge> }` in `approvedCharges`, keeping the other entries. For a bundle, repeat the call with `charge` as `approvedCharge`. Nothing was installed or bought. `dependencies_required` — The app needs other apps the site does not have yet; `plan` lists every app it needs, at any depth, and whether the site has it. Nothing was installed. Repeat the call with `installDependencies` to install the missing apps first, then the app, and approve the plan’s private-function calls. `dependency_unavailable` — The app needs an app that cannot be installed on this site: it is not in the app store and you are not in its organization, it is suspended or deleted, or it has no version the site may run, or it was removed from this site recently and must be restored or installed on its own first. `message` names it. Nothing was installed. `registry_budget` — The change would grow the site's app configuration past the size the site worker can deploy. Remove an app or an install, or shorten install labels and geo filters, then retry. `message` states the refusal. `sites_paused` — Blotout has paused this team’s sites, so nothing was deployed or installed. Every site of the team answers 410 until the pause ends, and uninstalls, switches and settings changes are still recorded. A payment does not end the pause; contact Blotout. `deploys_blocked` — Blotout has blocked this team’s deploys, so nothing was deployed or installed. The team’s live sites keep running, and uninstalls, switches and settings changes still roll out. A payment does not lift the block; contact Blotout.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["version_not_ready","version_not_approved","version_below_minimum","version_not_offered","cap_reached","subscription_item_limit","quota_reached","multiple_not_allowed","browser_budget","removal_pending","install_changed","app_suspended","app_taken_down","binding_conflict","schema_incompatible","variable_retype","linked","approval_required","acknowledgement_required","charge_approval_required","dependencies_required","dependency_unavailable","registry_budget","sites_paused","deploys_blocked"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"version_not_ready"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"plan":{"$ref":"#/components/schemas/AppDependencyPlan"},"charge":{"$ref":"#/components/schemas/AppChargeApproval"},"appSlug":{"type":"string","description":"With `charge_approval_required`: the app the charge belongs to.","example":"pixel-sync"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"delete":{"operationId":"uninstallSiteApp","tags":["Site apps"],"summary":"Uninstall an app","description":"Removes an app from the site. The app stops being listed immediately; its code, data, and secrets are removed in the background, and `removed: false` means a removal was already under way.\n\n#### How it works\n\nUninstalling an app leaves the apps it needs on the site.\n\n#### Required permissions\n\n- `domain:manage_domain_apps:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$","description":"Immutable slug of the app, as shown by the list operation.","example":"facebook-capi"},"required":true,"description":"Immutable slug of the app, as shown by the list operation.","name":"appSlug","in":"path"},{"schema":{"type":"string","enum":["true","false"],"description":"Set to `true` to uninstall an app that apps it needs also need, after a site manager accepts that they can stop working.","example":"true"},"required":false,"description":"Set to `true` to uninstall an app that apps it needs also need, after a site manager accepts that they can stop working.","name":"acknowledgeDependents","in":"query"}],"responses":{"200":{"description":"Whether a live installation was marked for removal.","content":{"application/json":{"schema":{"type":"object","properties":{"removed":{"type":"boolean","description":"Whether a live installation was marked for removal; false when it was already being removed.","example":true}},"required":["removed"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`linked` — The app’s storage is shared through a storage link: a child site binds this site’s objects, or this site binds a parent’s. `message` names the sites; change the link first, or make the change on the parent site. When a child site lacks an app the version needs, `message` names it; install it on that child first. `app_required_by` — Other apps on the site need this app: the versions they run declare it as a required dependency, and this app does not need them back. `requiredBy` lists their slugs and `message` names them. Nothing was removed. Uninstall those apps first, or move them to a version that does not need it. `dependents_affected` — Other apps on the site need this app, and this app also needs each of them, at any depth. Without it they can stop working. `requiredBy` lists their slugs and `message` names them. Nothing was removed. Repeat the call with `acknowledgeDependents=true` once a site manager accepts this. `removal_pending` — A deployment for the site is running. Nothing changed, so retry later.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["linked","app_required_by","dependents_affected","removal_pending"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"linked"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"requiredBy":{"type":"array","items":{"type":"string"},"description":"With `app_required_by` or `dependents_affected`: the slugs of the apps on the site that need this app.","example":["pixel"]}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/apps/{appSlug}/restore":{"post":{"operationId":"restoreSiteApp","tags":["Site apps"],"summary":"Restore a removed app","description":"Undoes a recent uninstall, bringing the app back on the version it was running with its installs, configuration, secrets and stored data intact.\n\n#### How it works\n\nA removal can only be undone for a limited window; once the removal starts destroying the app’s data this answers `not_found`, and installing the app again is the only option left. The app returns unconfigured only if it was, and the site runs it again in the background.\n\n#### Required permissions\n\n- `domain:manage_domain_apps:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$","description":"Immutable slug of the app, as shown by the list operation.","example":"facebook-capi"},"required":true,"description":"Immutable slug of the app, as shown by the list operation.","name":"appSlug","in":"path"}],"responses":{"200":{"description":"The installation that was brought back.","content":{"application/json":{"schema":{"type":"object","properties":{"domainAppId":{"type":"string","description":"Id of the installation that was brought back.","example":"6c5b4a39-2817-4d6e-9f0a-1b2c3d4e5f6a"}},"required":["domainAppId"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"402":{"description":"`no_payment_method` — The team pays by card and has no payment method on file, so nothing was deployed or installed. Add a card on the team’s Billing page, then retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["no_payment_method"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"no_payment_method"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`removal_pending` — A previous uninstall of this app is torn down as part of this call, and that teardown could not finish — because a deployment for the site is already running, or Cloudflare refused a delete. Nothing was left half-removed and the site's scheduled cleanup carries on, so retry. `registry_budget` — The change would grow the site's app configuration past the size the site worker can deploy. Remove an app or an install, or shorten install labels and geo filters, then retry. `message` states the refusal. `app_taken_down` — Blotout has taken this app down for good, so nothing changed. `message` states what the call cannot do. Do not retry. `dependencies_missing` — The version the app would come back on needs apps the site does not run: they are not installed, or were removed. A disabled app counts as installed. `missing` lists their slugs and `message` names them. Nothing was restored. Install those apps first, then restore again. `sites_paused` — Blotout has paused this team’s sites, so nothing was deployed or installed. Every site of the team answers 410 until the pause ends, and uninstalls, switches and settings changes are still recorded. A payment does not end the pause; contact Blotout. `deploys_blocked` — Blotout has blocked this team’s deploys, so nothing was deployed or installed. The team’s live sites keep running, and uninstalls, switches and settings changes still roll out. A payment does not lift the block; contact Blotout.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["removal_pending","registry_budget","app_taken_down","dependencies_missing","sites_paused","deploys_blocked"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"removal_pending"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"missing":{"type":"array","items":{"type":"string"},"description":"With `dependencies_missing`: the slugs of the apps the site must install first.","example":["consent"]}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/apps/{appSlug}/purge":{"post":{"operationId":"purgeRemovedSiteApp","tags":["Site apps"],"summary":"Delete a removed app now","description":"Deletes an uninstalled app’s configuration, installs, variables, secrets and stored data now, instead of at the end of the window in which the removal can be undone. To bring the app back instead, call the restore operation.\n\n#### How it works\n\nThe app can no longer be restored once this answers, and installing it again starts fresh. Its data is deleted in the background, usually within a few minutes. This cannot be undone. An app Blotout took down can be deleted too. `not_found` means the app has no removal left to undo: it is installed, was never installed on the site, or its deletion has already started.\n\n#### Required permissions\n\n- `domain:manage_domain_apps:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$","description":"Immutable slug of the app, as shown by the list operation.","example":"facebook-capi"},"required":true,"description":"Immutable slug of the app, as shown by the list operation.","name":"appSlug","in":"path"}],"responses":{"202":{"description":"The app can no longer be restored, and its data is being deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"accepted":{"type":"boolean","enum":[true],"description":"Always `true`: the app can no longer be restored, and its data is being deleted.","example":true}},"required":["accepted"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`removal_pending` — The site is still applying the uninstall (deploying it, or delivering the app’s `uninstalled` hook), or another deployment for the site is running. Nothing changed, so retry later.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["removal_pending"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"removal_pending"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/apps/{appSlug}/installs":{"get":{"operationId":"listSiteAppInstalls","tags":["Site apps"],"summary":"List an app’s installs","description":"Lists the installations of one app on a site, with the id each of the install-scoped operations addresses. An app installed once has exactly one.\n\n#### How it works\n\nRemoved installs are left out, and ordinals are permanent — a gap means an install was removed, not that one is missing.\n\n#### Required permissions\n\n- `domain:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$","description":"Immutable slug of the app, as shown by the list operation.","example":"facebook-capi"},"required":true,"description":"Immutable slug of the app, as shown by the list operation.","name":"appSlug","in":"path"}],"responses":{"200":{"description":"The app’s installs.","content":{"application/json":{"schema":{"type":"object","properties":{"installs":{"type":"array","items":{"$ref":"#/components/schemas/SiteAppInstallSummary"},"description":"The app’s live installs, in install order."}},"required":["installs"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"post":{"operationId":"createSiteAppInstall","tags":["Site apps"],"summary":"Create an app install","description":"Adds another installation of an app that is already on the site. Name it with `label`. Use this after the first install when the app allows more than one.\n\n#### How it works\n\nThe app must already be installed and allow multiple installs. The new install starts unconfigured — set its values, then deploy. `multiple_not_allowed` means the app only supports one; `install_limit` means the site is at the cap. Secret values are never returned.\n\n#### Required permissions\n\n- `domain:manage_domain_apps:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$","description":"Immutable slug of the app, as shown by the list operation.","example":"facebook-capi"},"required":true,"description":"Immutable slug of the app, as shown by the list operation.","name":"appSlug","in":"path"}],"requestBody":{"required":true,"description":"The name for the additional installation.","content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":100,"description":"The label every surface shows for this install. At most 100 characters.","example":"EU pixel"}},"required":["label"],"additionalProperties":{},"description":"The name for the additional installation. A `geoFilter` is refused as `invalid_body`: a new install runs in every location until the update operation sets one."}}}},"responses":{"201":{"description":"The additional install this call created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedSiteAppInstall"}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"402":{"description":"`no_payment_method` — The team pays by card and has no payment method on file, so nothing was deployed or installed. Add a card on the team’s Billing page, then retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["no_payment_method"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"no_payment_method"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`multiple_not_allowed` — The app allows only one install per site, or a version change would leave more installs than the target version allows. `message` states the conflict. `install_limit` — The site already has as many installs of this app as Qinto allows. Remove one, then retry. `message` states the cap. `variable_invalid` — The app declares no variable by that name, or another party sets the name (the site manager, the app developer, or the app’s own panel); `message` names it. `registry_budget` — The change would grow the site's app configuration past the size the site worker can deploy. Remove an app or an install, or shorten install labels and geo filters, then retry. `message` states the refusal. `app_suspended` — Blotout has suspended this app, so nothing ran and nothing changed. The call works again once the suspension is lifted. `app_taken_down` — Blotout has taken this app down for good, so nothing changed. `message` states what the call cannot do. Do not retry. `sites_paused` — Blotout has paused this team’s sites, so nothing was deployed or installed. Every site of the team answers 410 until the pause ends, and uninstalls, switches and settings changes are still recorded. A payment does not end the pause; contact Blotout. `deploys_blocked` — Blotout has blocked this team’s deploys, so nothing was deployed or installed. The team’s live sites keep running, and uninstalls, switches and settings changes still roll out. A payment does not lift the block; contact Blotout.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["multiple_not_allowed","install_limit","variable_invalid","registry_budget","app_suspended","app_taken_down","sites_paused","deploys_blocked"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"multiple_not_allowed"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/apps/{appSlug}/installs/{installId}":{"patch":{"operationId":"updateSiteAppInstall","tags":["Site apps"],"summary":"Update an app install","description":"Renames an install with `{ label }`, flips its own switch with `{ enabled }`, or sets where it runs with `{ geoFilter }`; `geoFilter: null` removes the geo filter. Send one of the three per call. The app-level kill switch is a different operation.\n\n#### How it works\n\nA call that repeats the stored value succeeds and changes nothing. Disabling one install leaves the others running. Geo filter lists are stored deduplicated and sorted. An unknown location, the same location in both lists, or a US state next to `US` in one list is refused as `invalid_body`, and `details` names the entry. An OAuth token’s user also needs an app role of `admin` or higher on the site.\n\n#### Required permissions\n\n- `domain:manage_domain_apps:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$","description":"Immutable slug of the app, as shown by the list operation.","example":"facebook-capi"},"required":true,"description":"Immutable slug of the app, as shown by the list operation.","name":"appSlug","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the installation, as returned by the installs operation.","example":"8d7c6b5a-4938-4271-a605-9e8f7a6b5c4d"},"required":true,"description":"Unique id (UUID) of the installation, as returned by the installs operation.","name":"installId","in":"path"}],"requestBody":{"required":true,"description":"The replacement label, the install-level switch, or the geo filter.","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":100,"description":"The replacement label.","example":"EU pixel"}},"required":["label"],"additionalProperties":false},{"type":"object","properties":{"enabled":{"type":"boolean","description":"The replacement install-level switch state.","example":false}},"required":["enabled"],"additionalProperties":false},{"type":"object","properties":{"geoFilter":{"anyOf":[{"$ref":"#/components/schemas/GeoFilter"},{"type":"null"}],"description":"The replacement geo filter, or null to remove it. Two empty lists also remove it.","example":{"include":["EU"],"exclude":[]}}},"required":["geoFilter"],"additionalProperties":false}],"description":"Exactly one of `{ label }` to rename the install, `{ enabled }` to flip its switch, or `{ geoFilter }` to set where it runs."}}}},"responses":{"200":{"description":"Whether the label, switch or geo filter actually changed.","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"boolean","description":"Whether the switch actually changed.","example":true}},"required":["updated"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`variable_invalid` — The app declares no variable by that name, or another party sets the name (the site manager, the app developer, or the app’s own panel); `message` names it. `registry_budget` — The change would grow the site's app configuration past the size the site worker can deploy. Remove an app or an install, or shorten install labels and geo filters, then retry. `message` states the refusal. `app_suspended` — Blotout has suspended this app, so nothing ran and nothing changed. The call works again once the suspension is lifted.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["variable_invalid","registry_budget","app_suspended"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"variable_invalid"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"delete":{"operationId":"deleteSiteAppInstall","tags":["Site apps"],"summary":"Remove an app install","description":"Removes one installation of an app that remains on the site. Removing an install does not uninstall the app.\n\n#### How it works\n\n`removed: false` means the install was already gone, so retries are safe. The app stays listed; its other installs are unchanged.\n\n#### Required permissions\n\n- `domain:manage_domain_apps:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$","description":"Immutable slug of the app, as shown by the list operation.","example":"facebook-capi"},"required":true,"description":"Immutable slug of the app, as shown by the list operation.","name":"appSlug","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the installation, as returned by the installs operation.","example":"8d7c6b5a-4938-4271-a605-9e8f7a6b5c4d"},"required":true,"description":"Unique id (UUID) of the installation, as returned by the installs operation.","name":"installId","in":"path"}],"responses":{"200":{"description":"Whether a live install was removed.","content":{"application/json":{"schema":{"type":"object","properties":{"removed":{"type":"boolean","description":"Whether a live install was tombstoned; false when it was already gone.","example":true}},"required":["removed"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/apps/{appSlug}/installs/{installId}/variables":{"put":{"operationId":"setSiteAppInstallVariables","tags":["Site apps"],"summary":"Configure an install","description":"Stores an installation’s configuration values — the settings the app declares in its manifest, including its secrets. Only the names in the body are written; anything left out keeps its current value.\n\n#### How it works\n\nA secret’s value is write-only and never returned by any operation. Completing the last required variable makes the install active, which redeploys the site in the background; a call that changes nothing does neither. An OAuth token’s user also needs an app role of `admin` or higher on the site.\n\n#### Required permissions\n\n- `domain:manage_domain_apps:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$","description":"Immutable slug of the app, as shown by the list operation.","example":"facebook-capi"},"required":true,"description":"Immutable slug of the app, as shown by the list operation.","name":"appSlug","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the installation, as returned by the installs operation.","example":"8d7c6b5a-4938-4271-a605-9e8f7a6b5c4d"},"required":true,"description":"Unique id (UUID) of the installation, as returned by the installs operation.","name":"installId","in":"path"}],"requestBody":{"required":true,"description":"The values to store, keyed by variable name.","content":{"application/json":{"schema":{"type":"object","properties":{"values":{"type":"object","additionalProperties":{"anyOf":[{"type":"string","description":"The value of a `text`, `password` or `select` variable.","example":"1234567890"},{"type":"boolean","description":"The value of a `toggle` variable.","example":true},{"type":"array","items":{"type":"string"},"description":"The value of a `multiselect` variable: option values, stored in manifest order.","example":["AddToCart","Purchase"]}]},"description":"The values to store, keyed by the variable name the app declares. A boolean variable takes `true`/`false`; a `select` takes an option `value`, or an empty string for none; a `multiselect` takes a list of option values, or an empty list for none.","example":{"PIXEL_ID":"1234567890"}}},"required":["values"],"description":"The install’s configuration values. A secret variable’s value is write-only and never read back."}}}},"responses":{"200":{"description":"The values were stored.","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"boolean","description":"Whether the switch actually changed.","example":true}},"required":["updated"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`variable_invalid` — The app declares no variable by that name, or another party sets the name (the site manager, the app developer, or the app’s own panel); `message` names it. `variable_too_large` — A value exceeds its serialized limit: 256 KB for a `large` variable, 5 KB for another variable of a single-install app, 490 bytes for one of an app that allows multiple installs or for an app-scope variable; `message` names the variable, its size and the limit. `variable_budget` — One variable’s values across every install of the app on this site exceed 5 KB together, or all `large` values of the app’s worker exceed 1 MB, removed installs included until they are purged; `message` states the size. Shorten a value before retrying; a removed install frees its share once it is purged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["variable_invalid","variable_too_large","variable_budget"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"variable_invalid"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/apps/{appSlug}/tools/{toolName}":{"patch":{"operationId":"setSiteAppTool","tags":["Site apps"],"summary":"Switch a tool on or off","description":"Decides whether AI assistants may call one of an installed app’s tools on this site. The app keeps running either way — only the assistant surface is affected.\n\n#### How it works\n\nA tool the site’s serving version does not declare is refused, so the list cannot collect names that no longer exist. Resubmitting the current state answers `updated: false` and records nothing. A tool switched off on this site stays available on other sites that still have it on. An OAuth token’s user also needs an app role of `admin` or higher on the site.\n\n#### Required permissions\n\n- `domain:manage_domain_apps:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$","description":"Immutable slug of the app, as shown by the list operation.","example":"facebook-capi"},"required":true,"description":"Immutable slug of the app, as shown by the list operation.","name":"appSlug","in":"path"},{"schema":{"type":"string","pattern":"^[a-zA-Z][a-zA-Z0-9_]{0,31}$","description":"The tool’s own name as the app’s manifest declares it, without the app-slug prefix.","example":"emqReport"},"required":true,"description":"The tool’s own name as the app’s manifest declares it, without the app-slug prefix.","name":"toolName","in":"path"}],"requestBody":{"required":true,"description":"The tool’s switch state.","content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether AI assistants may call this tool on this site. A newly approved tool starts enabled.","example":false}},"required":["enabled"],"description":"The tool’s per-site switch."}}}},"responses":{"200":{"description":"Whether the switch actually changed.","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"boolean","description":"Whether the switch actually changed.","example":true}},"required":["updated"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry. `tool_not_declared` — The version this site serves declares no tool by that name; `message` names it. A tool the app dropped cannot be switched, so the list never collects names that no longer exist.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found","tool_not_declared"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`app_suspended` — Blotout has suspended this app, so nothing ran and nothing changed. The call works again once the suspension is lifted.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["app_suspended"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"app_suspended"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"post":{"operationId":"callAppTool","tags":["Site apps"],"summary":"Call an app tool","description":"Runs one of an installed app’s tools against a site and returns what the app answered. The arguments are validated against the schema the version that site actually serves declares, so a tool is always called on the contract in front of it.\n\n#### How it works\n\nThe call runs as the caller, on the named site, in an app that site already installed. The caller’s app role on that site must reach the tool’s minimum role; an app they have no access to, or a tool above their role, answers `not_found` like one that does not exist. `installId` is required only where the app is installed more than once; `install_required` names the choices. A repeat is a new call: the platform neither retries nor deduplicates one. Every call is written to the team’s activity log, without its arguments. Requires an OAuth access token.\n\n#### Required permissions\n\n- `domain:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$","description":"Immutable slug of the app, as shown by the list operation.","example":"facebook-capi"},"required":true,"description":"Immutable slug of the app, as shown by the list operation.","name":"appSlug","in":"path"},{"schema":{"type":"string","pattern":"^[a-zA-Z][a-zA-Z0-9_]{0,31}$","description":"The tool’s own name as the app’s manifest declares it, without the app-slug prefix.","example":"emqReport"},"required":true,"description":"The tool’s own name as the app’s manifest declares it, without the app-slug prefix.","name":"toolName","in":"path"}],"requestBody":{"required":true,"description":"Which installation to act on, and the tool’s own arguments.","content":{"application/json":{"schema":{"type":"object","properties":{"installId":{"type":"string","format":"uuid","description":"Which installation to run the tool against. Required only where the app is installed more than once.","example":"8d7c6b5a-4938-4271-a605-9e8f7a6b5c4d"},"arguments":{"type":"object","additionalProperties":{},"default":{},"description":"The tool’s own arguments, validated against the schema its serving version declares.","example":{}}},"description":"Which installation to act on, and the tool’s own arguments."}}}},"responses":{"200":{"description":"What the tool answered.","content":{"application/json":{"schema":{"type":"object","properties":{"outcome":{"type":"string","enum":["ok","failed","error"],"description":"How the call ended: `ok` the app answered, `failed` it declined and `content` is its own message, `error` the platform could not complete it.","example":"ok"},"content":{"type":"string","description":"The app’s answer, as text.","example":"Resent 12 events."},"data":{"type":"object","additionalProperties":{},"description":"The app’s structured answer, when it returned one.","example":{"sent":12}}},"required":["outcome","content"],"description":"What the tool answered."}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed. `invalid_arguments` — The arguments do not match the schema the version this site serves declares; `message` names the offending property. Read the tool’s current schema before retrying.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body","invalid_arguments"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`not_deployed` — The site has never been deployed, so it has no host to describe yet. Deploy it, then retry. `tool_disabled` — A site manager has switched this tool off for the site, so assistants may not call it there. Nothing ran. `app_suspended` — Blotout has suspended this app, so nothing ran and nothing changed. The call works again once the suspension is lifted. `install_required` — The app is installed more than once on this site, so the call must name which installation to act on; `message` lists them with their ids. `install_inactive` — The named installation is switched off, so nothing was dispatched to it. Turn it on, then retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_deployed","tool_disabled","app_suspended","install_required","install_inactive"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_deployed"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"429":{"description":"`rate_limited` — Too many requests for this API token or site in a short window; wait a minute and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"rate_limited"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/app-events":{"get":{"operationId":"listAppEvents","tags":["Site analytics"],"summary":"Read app event counts","description":"Counts the events the site’s apps received over a time range, bucketed and grouped, so a delivery problem shows up as a shape rather than a guess.\n\n#### How it works\n\nBuckets are cut in the `timeZone` you pass, so a day boundary is the reader’s own, and every series carries a point for every bucket in the range — `0` where it recorded nothing. `state` says how the read ended: only `ok` carries points, `no_dataset` means the site has recorded nothing yet, and `too_broad` asks for a narrower range or a coarser bucket.\n\n#### Required permissions\n\n- `domain:analytics_dashboard:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","format":"date-time","description":"Start of the half-open range, as an ISO 8601 instant.","example":"2026-08-22T00:00:00.000Z"},"required":true,"description":"Start of the half-open range, as an ISO 8601 instant.","name":"start","in":"query"},{"schema":{"type":"string","format":"date-time","description":"End of the half-open range, exclusive, as an ISO 8601 instant.","example":"2026-08-29T00:00:00.000Z"},"required":true,"description":"End of the half-open range, exclusive, as an ISO 8601 instant.","name":"end","in":"query"},{"schema":{"type":"string","description":"IANA timezone the buckets are cut in, so a day boundary is the reader’s own.","example":"Europe/Ljubljana"},"required":true,"description":"IANA timezone the buckets are cut in, so a day boundary is the reader’s own.","name":"timeZone","in":"query"},{"schema":{"type":"string","description":"Report on one app only.","example":"facebook-capi"},"required":false,"description":"Report on one app only.","name":"appSlug","in":"query"},{"schema":{"type":"string","format":"uuid","description":"Report on one installation only.","example":"8d7c6b5a-4938-4271-a605-9e8f7a6b5c4d"},"required":false,"description":"Report on one installation only.","name":"appInstallId","in":"query"},{"schema":{"type":"string","enum":["minute","hour","day"],"description":"Bucket size. A wide range refuses the finer sizes rather than returning an unreadable series.","example":"hour"},"required":true,"description":"Bucket size. A wide range refuses the finer sizes rather than returning an unreadable series.","name":"granularity","in":"query"},{"schema":{"type":"string","enum":["status","event","install"],"description":"What each series counts: delivery `status`, the `event` name, or the `install` that received it.","example":"status"},"required":true,"description":"What each series counts: delivery `status`, the `event` name, or the `install` that received it.","name":"grouping","in":"query"},{"schema":{"type":"string","description":"Report on one delivery status only.","example":"success"},"required":false,"description":"Report on one delivery status only.","name":"status","in":"query"}],"responses":{"200":{"description":"The counts, or why there are none.","content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"string","enum":["ok","no_dataset","too_broad","forbidden","unavailable","rate_limited"],"description":"How the read ended. `no_dataset` means the site has recorded nothing yet, `too_broad` that the selection must be narrowed, and `unavailable` / `rate_limited` that the provider refused; only `ok` carries data.","example":"ok"},"points":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","format":"date-time","description":"Start of the bucket, as an ISO 8601 UTC timestamp.","example":"2026-08-28T10:00:00.000Z"},"series":{"type":"string","description":"Which series the count belongs to.","example":"success"},"count":{"type":"integer","description":"How many were recorded in this bucket.","example":42}},"required":["at","series","count"]},"description":"One point per bucket and series; empty unless `state` is `ok`."},"series":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"The series’ stable key.","example":"success"},"label":{"type":"string","description":"What to show a reader for this series.","example":"success"}},"required":["key","label"]},"description":"The series present in the range, in the order they should be shown."}},"required":["state","points","series"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/app-errors":{"get":{"operationId":"listAppErrors","tags":["Site analytics"],"summary":"Read app errors","description":"Lists the failures the site’s apps reported over a time range, newest first, each with the app’s own description of what it was doing.\n\n#### How it works\n\nPage with `cursorAt` and `cursorId` from the previous response’s `nextCursor`; a null cursor means the last page. `state` says how the read ended, and only `ok` carries records.\n\n#### Required permissions\n\n- `domain:realtime_logger:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","format":"date-time","description":"Start of the half-open range, as an ISO 8601 instant.","example":"2026-08-22T00:00:00.000Z"},"required":true,"description":"Start of the half-open range, as an ISO 8601 instant.","name":"start","in":"query"},{"schema":{"type":"string","format":"date-time","description":"End of the half-open range, exclusive, as an ISO 8601 instant.","example":"2026-08-29T00:00:00.000Z"},"required":true,"description":"End of the half-open range, exclusive, as an ISO 8601 instant.","name":"end","in":"query"},{"schema":{"type":"string","description":"IANA timezone the buckets are cut in, so a day boundary is the reader’s own.","example":"Europe/Ljubljana"},"required":true,"description":"IANA timezone the buckets are cut in, so a day boundary is the reader’s own.","name":"timeZone","in":"query"},{"schema":{"type":"string","description":"Report on one app only.","example":"facebook-capi"},"required":false,"description":"Report on one app only.","name":"appSlug","in":"query"},{"schema":{"type":"string","format":"uuid","description":"Report on one installation only.","example":"8d7c6b5a-4938-4271-a605-9e8f7a6b5c4d"},"required":false,"description":"Report on one installation only.","name":"appInstallId","in":"query"},{"schema":{"type":"string","description":"Report on one error category only.","example":"delivery"},"required":false,"description":"Report on one error category only.","name":"category","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"description":"How many records to return, 1–100.","example":50},"required":false,"description":"How many records to return, 1–100.","name":"limit","in":"query"},{"schema":{"type":"string","format":"date-time","description":"Continue after this record’s instant, from a previous response’s cursor.","example":"2026-08-28T23:59:59.000Z"},"required":false,"description":"Continue after this record’s instant, from a previous response’s cursor.","name":"cursorAt","in":"query"},{"schema":{"type":"string","description":"Continue after this record’s id, from a previous response’s cursor. Send it with `cursorAt`.","example":"9e8d7c6b-5a49-4382-b716-0f9e8d7c6b5a"},"required":false,"description":"Continue after this record’s id, from a previous response’s cursor. Send it with `cursorAt`.","name":"cursorId","in":"query"}],"responses":{"200":{"description":"The failures, or why there are none.","content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"string","enum":["ok","no_dataset","too_broad","forbidden","unavailable","rate_limited"],"description":"How the read ended. `no_dataset` means the site has recorded nothing yet, `too_broad` that the selection must be narrowed, and `unavailable` / `rate_limited` that the provider refused; only `ok` carries data.","example":"ok"},"records":{"type":"array","items":{"$ref":"#/components/schemas/AppErrorRecord"},"description":"The page of failures, newest first; empty unless `state` is `ok`."},"nextCursor":{"type":["object","null"],"properties":{"at":{"type":"string","description":"Pass as `cursorAt`.","example":"2026-08-28T23:59:59.000Z"},"id":{"type":"string","description":"Pass as `cursorId`.","example":"af31c0d2"}},"required":["at","id"],"description":"Where the next page starts, or null on the last one."}},"required":["state","records","nextCursor"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/app-errors/series":{"get":{"operationId":"countAppErrors","tags":["Site analytics"],"summary":"Count app errors","description":"Counts the failures the site’s apps reported over a time range, bucketed with one series per installation. Use it for totals and trends: the error list can leave out individual records, and these counts do not.\n\n#### How it works\n\nBuckets are cut in the `timeZone` you pass, and every series carries a point for every bucket in the range — `0` where nothing failed. `state` says how the read ended: only `ok` carries points, `no_dataset` means the site has recorded nothing yet, and `too_broad` asks for a narrower range or a coarser bucket.\n\n#### Required permissions\n\n- `domain:realtime_logger:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","format":"date-time","description":"Start of the half-open range, as an ISO 8601 instant.","example":"2026-08-22T00:00:00.000Z"},"required":true,"description":"Start of the half-open range, as an ISO 8601 instant.","name":"start","in":"query"},{"schema":{"type":"string","format":"date-time","description":"End of the half-open range, exclusive, as an ISO 8601 instant.","example":"2026-08-29T00:00:00.000Z"},"required":true,"description":"End of the half-open range, exclusive, as an ISO 8601 instant.","name":"end","in":"query"},{"schema":{"type":"string","description":"IANA timezone the buckets are cut in, so a day boundary is the reader’s own.","example":"Europe/Ljubljana"},"required":true,"description":"IANA timezone the buckets are cut in, so a day boundary is the reader’s own.","name":"timeZone","in":"query"},{"schema":{"type":"string","description":"Report on one app only.","example":"facebook-capi"},"required":false,"description":"Report on one app only.","name":"appSlug","in":"query"},{"schema":{"type":"string","format":"uuid","description":"Report on one installation only.","example":"8d7c6b5a-4938-4271-a605-9e8f7a6b5c4d"},"required":false,"description":"Report on one installation only.","name":"appInstallId","in":"query"},{"schema":{"type":"string","enum":["minute","hour","day"],"description":"Bucket size. A wide range refuses the finer sizes rather than returning an unreadable series.","example":"hour"},"required":true,"description":"Bucket size. A wide range refuses the finer sizes rather than returning an unreadable series.","name":"granularity","in":"query"},{"schema":{"type":"string","description":"Report on one error category only.","example":"delivery"},"required":false,"description":"Report on one error category only.","name":"category","in":"query"}],"responses":{"200":{"description":"The counts, or why there are none.","content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"string","enum":["ok","no_dataset","too_broad","forbidden","unavailable","rate_limited"],"description":"How the read ended. `no_dataset` means the site has recorded nothing yet, `too_broad` that the selection must be narrowed, and `unavailable` / `rate_limited` that the provider refused; only `ok` carries data.","example":"ok"},"points":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","format":"date-time","description":"Start of the bucket, as an ISO 8601 UTC timestamp.","example":"2026-08-28T10:00:00.000Z"},"series":{"type":"string","description":"Which series the count belongs to.","example":"success"},"count":{"type":"integer","description":"How many were recorded in this bucket.","example":42}},"required":["at","series","count"]},"description":"One point per bucket and series; empty unless `state` is `ok`."},"series":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"The series’ stable key.","example":"success"},"label":{"type":"string","description":"What to show a reader for this series.","example":"success"}},"required":["key","label"]},"description":"The series present in the range, in the order they should be shown."}},"required":["state","points","series"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/id-graph/metrics":{"get":{"operationId":"getIdGraphMetrics","tags":["Site analytics"],"summary":"Read ID graph metrics","description":"Reports the Durable Object usage of the site’s identity graph — the per-device Anon DO and the per-person Global DO — over a recent window, hour by hour, with the window before it for comparison.\n\n#### How it works\n\n`state: unavailable` is not a failure of the call: retry later, and if it persists, check that the host’s Cloudflare token can read analytics.\n\n#### Required permissions\n\n- `domain:id_graph_explorer:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"},{"schema":{"type":"string","enum":["1h","6h","24h","7d"],"default":"24h","description":"How far back to report, ending now. The previous window of the same length is reported alongside for comparison.","example":"24h"},"required":false,"description":"How far back to report, ending now. The previous window of the same length is reported alongside for comparison.","name":"window","in":"query"}],"responses":{"200":{"description":"The usage, or why there is none.","content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"string","enum":["ok","unavailable"],"description":"`unavailable` when the metrics cannot be read right now — the host’s token cannot read analytics, the read quota is spent, or Cloudflare refused — and `namespaces` is empty then.","example":"ok"},"window":{"type":"string","enum":["1h","6h","24h","7d"],"description":"The window reported.","example":"24h"},"namespaces":{"type":"array","items":{"$ref":"#/components/schemas/IdGraphNamespaceMetrics"},"description":"One entry per class the site has recorded; empty unless `state` is `ok`."}},"required":["state","window","namespaces"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/id-graph/resolve":{"post":{"operationId":"resolveIdentity","tags":["Sites"],"summary":"Resolve an identity","description":"Turns something you can type — an anon id, a `gid_`, or a raw identifier such as an email address — into the name of the identity-graph object that holds it. Every other identity operation addresses that name.\n\n#### How it works\n\nA `null` name means nothing on this site owns that input. It is a POST so a raw identifier never appears in a URL.\n\n#### Required permissions\n\n- `domain:id_graph_explorer:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"}],"requestBody":{"required":true,"description":"What to look up.","content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["anon","alias","global"],"description":"Which object to open: `anon` a browser profile, `alias` one identifier’s mapping, `global` the person an anon id or identifier resolves to.","example":"anon"},"input":{"type":"string","minLength":1,"maxLength":512,"description":"An anon id, a `gid_`, or a raw identifier such as an email address.","example":"buyer@example.com"}},"required":["kind","input"],"description":"What to look up, and which object to resolve it to."}}}},"responses":{"200":{"description":"The object name, or null.","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":["string","null"],"description":"The object’s name, to pass to the inspect and rows operations; null when nothing owns that input.","example":"anon_9f2c"}},"required":["name"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`not_deployed` — The site has never been deployed, so it has no host to describe yet. Deploy it, then retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_deployed"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_deployed"}},"required":["error"]}}}},"422":{"description":"`host_not_ready` — The site’s host is not ready to serve it — no Cloudflare zone chosen, no stored API token, a token scoped to the wrong zone, a conflicting DNS record, or a dispatcher that refused the request. `message` names the fix.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["host_not_ready"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"host_not_ready"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}},"502":{"description":"`worker_unreachable` — The site’s own worker could not be reached or refused the request, so nothing could be read from it; `message` says what failed. Retry once the site is serving again.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["worker_unreachable"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"worker_unreachable"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/id-graph/inspect":{"post":{"operationId":"inspectIdentity","tags":["Sites"],"summary":"Inspect an identity","description":"Dumps one identity-graph object: everything stored against it, and the tables it holds with their sizes. Use it to see what a visitor profile actually contains after a delivery looks wrong.\n\n#### How it works\n\n`exists: false` means the name was never written to — resolve it first. Table contents are read separately, one page at a time, with the rows operation.\n\n#### Required permissions\n\n- `domain:id_graph_explorer:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"}],"requestBody":{"required":true,"description":"Which object to dump.","content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["anon","alias","global"],"description":"Which object to open: `anon` a browser profile, `alias` one identifier’s mapping, `global` the person an anon id or identifier resolves to.","example":"anon"},"name":{"type":"string","minLength":1,"maxLength":512,"description":"The object name from the resolve operation.","example":"anon_9f2c"}},"required":["kind","name"],"description":"Which object to dump."}}}},"responses":{"200":{"description":"The object’s stored state.","content":{"application/json":{"schema":{"type":"object","properties":{"exists":{"type":"boolean","description":"False for a name nothing ever wrote to.","example":true},"objectId":{"type":["string","null"],"description":"The Durable Object’s id; null when it does not exist.","example":"a1b2c3d4"},"databaseSize":{"type":"integer","description":"How many bytes the object’s SQL storage holds.","example":16384},"kv":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"The stored key.","example":"profile"},"value":{"description":"The stored value, as it was written.","example":{"seenAt":1787000000000}}},"required":["key"]},"description":"The object’s key-value entries."},"tables":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"The table’s name; pass it to the rows operation.","example":"events"},"columns":{"type":"array","items":{"type":"string"},"description":"The table’s columns, in order.","example":["at","name"]},"rowCount":{"type":"integer","description":"How many rows the table holds.","example":128}},"required":["name","columns","rowCount"]},"description":"The object’s tables and their sizes."}},"required":["exists","objectId","databaseSize","kv","tables"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`not_deployed` — The site has never been deployed, so it has no host to describe yet. Deploy it, then retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_deployed"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_deployed"}},"required":["error"]}}}},"422":{"description":"`host_not_ready` — The site’s host is not ready to serve it — no Cloudflare zone chosen, no stored API token, a token scoped to the wrong zone, a conflicting DNS record, or a dispatcher that refused the request. `message` names the fix.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["host_not_ready"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"host_not_ready"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}},"502":{"description":"`worker_unreachable` — The site’s own worker could not be reached or refused the request, so nothing could be read from it; `message` says what failed. Retry once the site is serving again.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["worker_unreachable"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"worker_unreachable"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/id-graph/rows":{"post":{"operationId":"readIdentityTable","tags":["Sites"],"summary":"Read identity table rows","description":"Reads one page of a table inside an identity-graph object, so you can see the rows behind a count the inspect operation gave you.\n\n#### How it works\n\nPages are 100 rows; advance with `offset`, and compare it against `rowCount` to know when you have read everything. `found: false` means the object or the table does not exist.\n\n#### Required permissions\n\n- `domain:id_graph_explorer:read` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"}],"requestBody":{"required":true,"description":"Which table to page.","content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["anon","alias","global"],"description":"Which object to open: `anon` a browser profile, `alias` one identifier’s mapping, `global` the person an anon id or identifier resolves to.","example":"anon"},"name":{"type":"string","minLength":1,"maxLength":512,"description":"The object name from the resolve operation.","example":"anon_9f2c"},"table":{"type":"string","minLength":1,"maxLength":128,"description":"The table to read, from the inspect operation.","example":"events"},"offset":{"type":"integer","minimum":0,"default":0,"description":"How many rows to skip.","example":0}},"required":["kind","name","table"],"description":"Which table of which object to page through."}}}},"responses":{"200":{"description":"The page of rows.","content":{"application/json":{"schema":{"type":"object","properties":{"found":{"type":"boolean","description":"False when the object or the table does not exist.","example":true},"columns":{"type":"array","items":{"type":"string"},"description":"The columns, in order.","example":["at","name"]},"rows":{"type":"array","items":{"type":"object","additionalProperties":{}},"description":"The page of rows, keyed by column name."},"rowCount":{"type":"integer","description":"How many rows the table holds in total.","example":128}},"required":["found","columns","rows","rowCount"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`not_deployed` — The site has never been deployed, so it has no host to describe yet. Deploy it, then retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_deployed"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_deployed"}},"required":["error"]}}}},"422":{"description":"`host_not_ready` — The site’s host is not ready to serve it — no Cloudflare zone chosen, no stored API token, a token scoped to the wrong zone, a conflicting DNS record, or a dispatcher that refused the request. `message` names the fix.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["host_not_ready"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"host_not_ready"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}},"502":{"description":"`worker_unreachable` — The site’s own worker could not be reached or refused the request, so nothing could be read from it; `message` says what failed. Retry once the site is serving again.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["worker_unreachable"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"worker_unreachable"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/visitor-data/preview":{"post":{"operationId":"previewDeleteRequest","tags":["Sites"],"summary":"Preview a delete request","description":"Shows what a delete request for one value from an end user’s GDPR request would erase, without erasing anything. Call it before the delete operation to check the value, or to learn that the site stores nothing about it.\n\n#### How it works\n\nThe value is sent to the Blotout platform only to find the person it belongs to; it is not stored. The counts cover the whole person, not only the value sent. `nothingStored: true` means there is nothing to erase.\n\n#### Required permissions\n\n- `domain:visitor_data:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"}],"requestBody":{"required":true,"description":"The value to look up.","content":{"application/json":{"schema":{"type":"object","properties":{"value":{"type":"string","minLength":1,"maxLength":512,"description":"One value from the end user’s request: an anon id, a person id (`gid_`), an email address, a phone number in international format (leading `+`), or a custom id. The kind is detected from the value.","example":"ada@example.com"}},"required":["value"],"description":"The value to look up."}}}},"responses":{"200":{"description":"What a delete request would erase, and who it would affect.","content":{"application/json":{"schema":{"type":"object","properties":{"inputType":{"type":"string","enum":["anon","person","email","phone","custom"],"description":"The kind of value the Blotout platform detected: an anon id, a person id, or an email, phone or custom id alias.","example":"email"},"counts":{"$ref":"#/components/schemas/DeleteRequestCounts"},"nothingStored":{"type":"boolean","description":"True when the site stores no data about the value; every count is then 0.","example":false},"sharedSites":{"type":"array","items":{"$ref":"#/components/schemas/SharedSite"},"description":"The sites that share this site’s identity graph through a storage link, the link parent first. The erase affects all of them. Empty when no other site shares the graph."},"installs":{"type":"array","items":{"type":"object","properties":{"appInstallId":{"type":"string","description":"The app install’s id.","example":"7c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f"},"domainId":{"type":"string","description":"The id of the site the install is on.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"domain":{"type":"string","description":"The hostname of the site the install is on.","example":"shop.example.com"},"appName":{"type":"string","description":"The app’s name.","example":"Meta Conversions"},"label":{"type":"string","description":"The install’s label.","example":"EU pixel"}},"required":["appInstallId","domainId","domain","appName","label"]},"description":"The app installs that would be asked to erase the person, enabled or not, on every site that shares the graph. Empty when no person or anon is stored."}},"required":["inputType","counts","nothingStored","sharedSites","installs"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`not_deployed` — The site has never been deployed, so it has no host to describe yet. Deploy it, then retry. `worker_outdated` — The site runs a worker from before delete requests, so nothing was read or erased. Deploy the site, then retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_deployed","worker_outdated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_deployed"}},"required":["error"]}}}},"422":{"description":"`host_not_ready` — The site’s host is not ready to serve it — no Cloudflare zone chosen, no stored API token, a token scoped to the wrong zone, a conflicting DNS record, or a dispatcher that refused the request. `message` names the fix.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["host_not_ready"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"host_not_ready"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}},"502":{"description":"`worker_unreachable` — The site’s own worker could not be reached or refused the request, so nothing could be read from it; `message` says what failed. Retry once the site is serving again.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["worker_unreachable"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"worker_unreachable"}},"required":["error"]}}}}}}},"/teams/{teamId}/domains/{domainId}/visitor-data/delete":{"post":{"operationId":"runDeleteRequest","tags":["Sites"],"summary":"Run a delete request","description":"Erases the whole person one value from an end user’s GDPR request belongs to, on this site and on every site that shares its visitor data, and asks the installed apps to erase the person too. It cannot be undone; preview the value first.\n\n#### How it works\n\nThe value is looked up again when the request runs, so the result does not depend on an earlier preview. Each run is recorded in the activity log with the counts and your reference, never the value. `partly_deleted` means the erase stopped partway: send the same value again to finish it. A second run erases only what is left.\n\n#### Required permissions\n\n- `domain:visitor_data:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the site operations.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the site operations.","name":"domainId","in":"path"}],"requestBody":{"required":true,"description":"The value to erase, and an optional reference.","content":{"application/json":{"schema":{"type":"object","properties":{"value":{"type":"string","minLength":1,"maxLength":512,"description":"One value from the end user’s request: an anon id, a person id (`gid_`), an email address, a phone number in international format (leading `+`), or a custom id. The kind is detected from the value.","example":"ada@example.com"},"reference":{"type":"string","maxLength":200,"description":"Your own reference for the request, such as a ticket number. It is stored in the activity log entry; omit it or send it blank for none.","example":"TICKET-42"}},"required":["value"],"description":"The value to erase, and an optional reference."}}}},"responses":{"200":{"description":"What was erased, and how many app installs were asked to erase the person.","content":{"application/json":{"schema":{"type":"object","properties":{"inputType":{"type":"string","enum":["anon","person","email","phone","custom"],"description":"The kind of value the Blotout platform detected: an anon id, a person id, or an email, phone or custom id alias.","example":"email"},"counts":{"$ref":"#/components/schemas/DeleteRequestCounts"},"nothingStored":{"type":"boolean","description":"True when the site stores no data about the value; every count is then 0.","example":false},"sharedSites":{"type":"array","items":{"$ref":"#/components/schemas/SharedSite"},"description":"The sites that share this site’s identity graph through a storage link, the link parent first. The erase affects all of them. Empty when no other site shares the graph."},"installsNotified":{"type":"integer","description":"How many app installs were asked to erase the person.","example":2},"reference":{"type":["string","null"],"description":"The reference as stored, trimmed; null when none was sent.","example":"TICKET-42"}},"required":["inputType","counts","nothingStored","sharedSites","installsNotified","reference"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`not_deployed` — The site has never been deployed, so it has no host to describe yet. Deploy it, then retry. `worker_outdated` — The site runs a worker from before delete requests, so nothing was read or erased. Deploy the site, then retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_deployed","worker_outdated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_deployed"}},"required":["error"]}}}},"422":{"description":"`host_not_ready` — The site’s host is not ready to serve it — no Cloudflare zone chosen, no stored API token, a token scoped to the wrong zone, a conflicting DNS record, or a dispatcher that refused the request. `message` names the fix.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["host_not_ready"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"host_not_ready"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}},"502":{"description":"`worker_unreachable` — The site’s own worker could not be reached or refused the request, so nothing could be read from it; `message` says what failed. Retry once the site is serving again. `partly_deleted` — The site’s worker stopped the erase before it finished, so part of the data may already be erased. The app installs were still asked to erase the person. Send the same value again to finish it; a second run erases only what is left.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["worker_unreachable","partly_deleted"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"worker_unreachable"}},"required":["error"]}}}}}}},"/teams/{teamId}/activity":{"get":{"operationId":"listActivity","tags":["Team members"],"summary":"List team activity","description":"Lists the team’s audit trail newest first: every change a person or a credential made, with who made it and what it named at the time.\n\n#### How it works\n\nFilter to one site with `domainId`, or to one resource kind with `category`. Page with `cursorAt` and `cursorId` from the previous response’s `nextCursor`; a null cursor means the last page. Names in `metadata` are snapshots, so an entry still reads correctly after the resource is renamed or deleted.\n\n#### Required permissions\n\n- `team:view_activity_log:read` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"List one site’s entries only. Team-level changes carry no site and are then left out.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":false,"description":"List one site’s entries only. Team-level changes carry no site and are then left out.","name":"domainId","in":"query"},{"schema":{"type":"string","description":"List one resource kind only — the segment of `action` before the first dot.","example":"domain_app"},"required":false,"description":"List one resource kind only — the segment of `action` before the first dot.","name":"category","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many entries to return, 1–200.","example":50},"required":false,"description":"How many entries to return, 1–200.","name":"limit","in":"query"},{"schema":{"type":"string","format":"date-time","description":"Continue after this entry’s instant, from a previous response’s cursor.","example":"2026-08-28T23:59:59.000Z"},"required":false,"description":"Continue after this entry’s instant, from a previous response’s cursor.","name":"cursorAt","in":"query"},{"schema":{"type":"string","description":"Continue after this entry’s id, from a previous response’s cursor. Send it with `cursorAt`.","example":"9e8d7c6b-5a49-4382-b716-0f9e8d7c6b5a"},"required":false,"description":"Continue after this entry’s id, from a previous response’s cursor. Send it with `cursorAt`.","name":"cursorId","in":"query"}],"responses":{"200":{"description":"The page of entries.","content":{"application/json":{"schema":{"type":"object","properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/ActivityEntry"},"description":"The page of entries, newest first."},"nextCursor":{"type":["object","null"],"properties":{"at":{"type":"string","description":"Pass as `cursorAt`.","example":"2026-08-28T23:59:59.000Z"},"id":{"type":"string","description":"Pass as `cursorId`.","example":"9e8d7c6b-5a49-4382-b716-0f9e8d7c6b5a"}},"required":["at","id"],"description":"Where the next page starts, or null on the last one."}},"required":["records","nextCursor"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/billing":{"get":{"operationId":"getBillingReport","tags":["Billing"],"summary":"Get the billing report","description":"Reads what the team pays for the Blotout platform this month: the core usage charges so far and projected with each site’s share, what each app and each bundle purchase charges so far and projected with their sites, when the team is charged next, how it pays, and its past invoices. Call it to follow a team’s costs without the Billing page.\n\n#### How it works\n\nThe amounts match the team’s Billing page, at list prices. Core usage settles two days late, so `soFar` counts up to `countedUntil`; app and bundle charges count through yesterday. Each list pages with the cursor of its name: `sitesAfter`, `invoicesAfter`, `appsAfter`, `bundlesAfter`, and `app` with `appSitesAfter` or `bundle` with `bundleSitesAfter` for one line’s sites. For a team Blotout has taken out of billing, the report says only `notBilled: true`. The report is read-only and sets up nothing: a team that has not opened its Billing page yet has no payment method, card terms, no next charge and no invoices.\n\n#### Required permissions\n\n- `team:manage_billing:read` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","minLength":1,"description":"Continue the sites after this one, from the previous response’s `sites.nextCursor`.","example":"shop.example.com"},"required":false,"description":"Continue the sites after this one, from the previous response’s `sites.nextCursor`.","name":"sitesAfter","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Continue the invoices after this one, from the previous response’s `invoices.nextCursor`.","example":"in_1QaBcDeFgHiJkLmN"},"required":false,"description":"Continue the invoices after this one, from the previous response’s `invoices.nextCursor`.","name":"invoicesAfter","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Continue the app lines after this app’s slug, from the previous response’s `apps.lines.nextCursor`.","example":"order-sync"},"required":false,"description":"Continue the app lines after this app’s slug, from the previous response’s `apps.lines.nextCursor`.","name":"appsAfter","in":"query"},{"schema":{"type":"string","minLength":1,"description":"The slug of the app whose sites `appSitesAfter` continues; it takes effect only together with `appSitesAfter`.","example":"order-sync"},"required":false,"description":"The slug of the app whose sites `appSitesAfter` continues; it takes effect only together with `appSitesAfter`.","name":"app","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Continue the sites of the app named in `app` after this one, from that line’s `sites.nextCursor`.","example":"shop.example.com"},"required":false,"description":"Continue the sites of the app named in `app` after this one, from that line’s `sites.nextCursor`.","name":"appSitesAfter","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Continue the bundle lines after this purchase’s id, from the previous response’s `bundles.lines.nextCursor`.","example":"9b1e2c4d-7f36-4a2e-9c1d-2e5f8a7b6c3d"},"required":false,"description":"Continue the bundle lines after this purchase’s id, from the previous response’s `bundles.lines.nextCursor`.","name":"bundlesAfter","in":"query"},{"schema":{"type":"string","minLength":1,"description":"The id of the bundle purchase whose sites `bundleSitesAfter` continues; it takes effect only together with `bundleSitesAfter`.","example":"9b1e2c4d-7f36-4a2e-9c1d-2e5f8a7b6c3d"},"required":false,"description":"The id of the bundle purchase whose sites `bundleSitesAfter` continues; it takes effect only together with `bundleSitesAfter`.","name":"bundle","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Continue the sites of the purchase named in `bundle` after this one, from that line’s `sites.nextCursor`.","example":"shop.example.com"},"required":false,"description":"Continue the sites of the purchase named in `bundle` after this one, from that line’s `sites.nextCursor`.","name":"bundleSitesAfter","in":"query"}],"responses":{"200":{"description":"The billing report.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingReport"}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}},"502":{"description":"`billing_unavailable` — The payment provider, which holds the team’s next charge date and invoices, could not be reached or refused the request, so no report was read. Retry in a few minutes.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["billing_unavailable"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"billing_unavailable"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}}}}},"/teams/{teamId}/bundle-purchases":{"get":{"operationId":"listBundlePurchases","tags":["Bundle purchases"],"summary":"List bundle purchases","description":"Lists the bundles the team bought, newest first, each with the terms copied when it was bought, the sites it covers, who accepted the charge and the terms, and when it started and ended. Call it to see what the team holds before you buy or install.\n\n#### How it works\n\nEnded purchases stay in the list with `endedAt` set; an active one has `endedAt` null. Narrow to one bundle with `bundleId`. Page with `cursorCreatedAt` and `cursorId` from the previous response’s `nextCursor`; a null cursor means the last page. Only a token with a user lists; a team API token is refused.\n\n#### Required permissions\n\n- `team:read` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Return only the purchases of this bundle.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"required":false,"description":"Return only the purchases of this bundle.","name":"bundleId","in":"query"},{"schema":{"type":"string","format":"date-time","description":"The `nextCursor.createdAt` of the previous page.","example":"2026-11-05T12:00:00.000Z"},"required":false,"description":"The `nextCursor.createdAt` of the previous page.","name":"cursorCreatedAt","in":"query"},{"schema":{"type":"string","description":"The `nextCursor.id` of the previous page.","example":"9c1d2e3f-4a5b-4c6d-8e7f-0a1b2c3d4e5f"},"required":false,"description":"The `nextCursor.id` of the previous page.","name":"cursorId","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"description":"Page size, 1–200 (default 50).","example":50},"required":false,"description":"Page size, 1–200 (default 50).","name":"limit","in":"query"}],"responses":{"200":{"description":"The page of purchases.","content":{"application/json":{"schema":{"type":"object","properties":{"purchases":{"type":"array","items":{"$ref":"#/components/schemas/BundlePurchase"},"description":"One page of the team’s purchases, newest first, ended ones included."},"nextCursor":{"type":["object","null"],"properties":{"createdAt":{"type":"string","description":"Start instant of the last listed purchase.","example":"2026-11-05T12:00:00.000Z"},"id":{"type":"string","description":"Id of the last listed purchase.","example":"9c1d2e3f-4a5b-4c6d-8e7f-0a1b2c3d4e5f"}},"required":["createdAt","id"],"description":"Pass both fields as `cursorCreatedAt` / `cursorId` for the next page; `null` on the last page."}},"required":["purchases","nextCursor"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"post":{"operationId":"buyBundle","tags":["Bundle purchases"],"summary":"Buy a bundle","description":"Buys a bundle for the team on the sites you choose, from the app store by `bundleId` or through a bundle link by `linkToken`. The purchase copies the bundle’s terms as they stand, so a later change to the bundle never reaches it. Buying installs no app: the team installs the bundle’s apps when it wants, at no charge beyond the bundle.\n\n#### How it works\n\nThe caller needs `manage_domain_apps` on every site named, and `purchase_apps` on the credential to approve a charge. `charge_approval_required` carries `charge`: the fee per interval, the monthly usage cap, the interval and the free days. Repeat the call with `charge` as `approvedCharge` once a person has accepted it. `acceptTerms` must be true. A link purchase uses up one of the link’s purchases, also for a free bundle. Existing installs of the bundle’s apps on the chosen sites keep their settings and charge the bundle’s terms from the next UTC day. A team holds at most one active purchase of a bundle. A team API token is refused.\n\n#### Required permissions\n\n- `domain:manage_domain_apps:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"}],"requestBody":{"required":true,"description":"The offer, the sites to cover, the charge approval and the terms acceptance.","content":{"application/json":{"schema":{"type":"object","properties":{"bundleId":{"type":"string","format":"uuid","description":"A Live public bundle from the app store. Pass this or `linkToken`.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"linkToken":{"type":"string","minLength":1,"maxLength":200,"description":"The `token` of a bundle link a developer shared. Pass this or `bundleId`.","example":"bl_7f3a1c92"},"domainIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":200,"description":"The sites the bundle covers, by id. The caller needs `manage_domain_apps` on each one; duplicates are collapsed.","example":["3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"]},"approvedCharge":{"type":"object","properties":{"feeCents":{"type":"integer","minimum":0,"description":"The most the call charges per interval, in US cents: for a purchase, the price plus the extra sites past the limit; for an added site, the extra-site price.","example":3900},"monthlyUsageCapCents":{"type":"integer","minimum":0,"description":"The most the bundle’s usage can charge in one month, in US cents, whatever the interval; 0 when it has no usage cap.","example":2000},"interval":{"type":"string","enum":["monthly","yearly","one_time"],"description":"The interval the fee is per.","example":"monthly"},"trialDays":{"type":"integer","minimum":0,"description":"The free days before the first charge; 0 when the bundle has no trial or it is over.","example":14}},"required":["feeCents","monthlyUsageCapCents","interval","trialDays"],"description":"The charge a person was shown, sent back as `charge_approval_required` gave it. Needed when the call charges. The call answers `charge_approval_required` with the current charge when it is missing, the fee or usage cap went up, the free days went down or the interval changed since it was shown.","example":{"feeCents":3900,"monthlyUsageCapCents":2000,"interval":"monthly","trialDays":14}},"acceptTerms":{"type":"boolean","description":"Accepts the terms and privacy policies of the bundle’s apps. Must be true.","example":true}},"required":["domainIds","acceptTerms"]}}}},"responses":{"201":{"description":"The purchase.","content":{"application/json":{"schema":{"type":"object","properties":{"purchase":{"$ref":"#/components/schemas/BundlePurchase"}},"required":["purchase"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"402":{"description":"`no_payment_method` — The team pays by card and has no payment method on file, so nothing was deployed or installed. Add a card on the team’s Billing page, then retry. `team_unpaid` — The team has an unpaid invoice, so it cannot install or enable an app that charges, buy a bundle, or add a site that charges. Nothing changed. Pay what is owed on the team’s Billing page, then retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["no_payment_method","team_unpaid"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"no_payment_method"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`bundle_link_revoked` — The link is revoked, which is permanent: the developer can’t change it and a team can’t buy through it. Nothing changed. The developer creates a new link instead. `bundle_link_used_up` — Every purchase the link allowed has been made, so the team can’t buy through it. Nothing changed. Ask the developer for a new link. `bundle_not_for_sale` — The bundle behind the link is Paused or Retired, or cannot be sold right now. Nothing changed. `bundle_already_purchased` — The team already holds this bundle. Nothing changed. A team holds at most one active purchase of a bundle. `bundle_site_limit` — The sites exceed the bundle’s site limit and the bundle sells no extra sites. Nothing changed. Choose fewer sites; the other sites install apps at the apps’ own prices. `charge_approval_required` — The call charges the team and did not approve that charge, or the charge went up, or its free days went down, after it was shown. `charge` holds the current charge and `message` states it. For an app, `appSlug` names the app the charge belongs to: once a person allowed to purchase apps accepts the charge and the developer’s terms, repeat the call with `{ \"<appSlug>\": <charge> }` in `approvedCharges`, keeping the other entries. For a bundle, repeat the call with `charge` as `approvedCharge`. Nothing was installed or bought. `terms_required` — The purchase needs the buyer to accept the terms of the bundle’s apps. Nothing changed. Repeat the call with `acceptTerms` once a person has read them. `subscription_item_limit` — The team’s Stripe subscription holds the most lines it can, so no further app or bundle that charges can be added to it; `message` names the app or bundle. Nothing was installed or bought. Contact support. `sites_paused` — Blotout has paused this team’s sites, so nothing was deployed or installed. Every site of the team answers 410 until the pause ends, and uninstalls, switches and settings changes are still recorded. A payment does not end the pause; contact Blotout. `deploys_blocked` — Blotout has blocked this team’s deploys, so nothing was deployed or installed. The team’s live sites keep running, and uninstalls, switches and settings changes still roll out. A payment does not lift the block; contact Blotout.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["bundle_link_revoked","bundle_link_used_up","bundle_not_for_sale","bundle_already_purchased","bundle_site_limit","charge_approval_required","terms_required","subscription_item_limit","sites_paused","deploys_blocked"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"bundle_link_revoked"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"charge":{"$ref":"#/components/schemas/BundleChargeApproval"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/bundle-purchases/{bundlePurchaseId}/apps":{"get":{"operationId":"listBundlePurchaseApps","tags":["Bundle purchases"],"summary":"List a purchase’s apps","description":"Reads a bundle purchase with the apps it covers right now and the sites each one is installed on. Call it to choose what to install with the install operation, at no charge beyond the bundle.\n\n#### How it works\n\nThe apps are those of the bundle’s developer that the purchase covers, with the version an install would take and whether that version runs without visitor consent. An app that joined the bundle after the purchase is listed like any other. An ended purchase lists no app. Only a token with a user reads; a team API token is refused.\n\n#### Required permissions\n\n- `team:read` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the purchase, as the list operation returns it.","example":"9c1d2e3f-4a5b-4c6d-8e7f-0a1b2c3d4e5f"},"required":true,"description":"Unique id (UUID) of the purchase, as the list operation returns it.","name":"bundlePurchaseId","in":"path"}],"responses":{"200":{"description":"The purchase and its apps.","content":{"application/json":{"schema":{"type":"object","properties":{"purchase":{"$ref":"#/components/schemas/BundlePurchase"},"apps":{"type":"array","items":{"$ref":"#/components/schemas/BundlePurchaseApp"},"description":"The apps the purchase covers right now, A–Z by name; empty once it ended."}},"required":["purchase","apps"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"post":{"operationId":"installBundleApps","tags":["Bundle purchases"],"summary":"Install a purchase’s apps","description":"Installs the chosen apps of a bundle purchase on every site the purchase covers, at no charge beyond the bundle: step 2 of buying a bundle, which the team can run at any time. A site that already runs an app keeps it as it is.\n\n#### How it works\n\nThe installs commit together, and the sites update in the background. `acknowledgement_required` names an app that runs without visitor consent; repeat the call with its slug in `acknowledgeNecessary`. `dependencies_required` carries the plan of the apps outside your choice the chosen apps need; repeat with `installDependencies`. Such an app outside the bundle installs at its own price, so `charge_approval_required` gives the `charge` for `approvedCharges`. `cap_reached` names the site that would go over 50 apps, and nothing is installed. The caller needs `manage_domain_apps` on every covered site; a team API token is refused.\n\n#### Required permissions\n\n- `domain:manage_domain_apps:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the purchase, as the list operation returns it.","example":"9c1d2e3f-4a5b-4c6d-8e7f-0a1b2c3d4e5f"},"required":true,"description":"Unique id (UUID) of the purchase, as the list operation returns it.","name":"bundlePurchaseId","in":"path"}],"requestBody":{"required":true,"description":"The covered apps to install and the confirmations the operation may require.","content":{"application/json":{"schema":{"type":"object","properties":{"appSlugs":{"type":"array","items":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$","description":"Slug of an app the purchase covers, as the apps operation returns it.","example":"facebook-capi"},"minItems":1,"maxItems":50,"description":"The covered apps to install on every site the purchase covers; duplicates are collapsed."},"installDependencies":{"type":"boolean","description":"Confirms the apps outside your choice that the chosen apps need, which install with them; required when the call answers `dependencies_required`.","example":false},"acknowledgeNecessary":{"type":"array","items":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$","description":"Slug of an app the purchase covers, as the apps operation returns it.","example":"facebook-capi"},"maxItems":60,"description":"Slugs of the apps that run without visitor consent, among the chosen apps and the apps they need, that a person acknowledged.","example":[]},"approvedCharges":{"type":"object","additionalProperties":{"allOf":[{"$ref":"#/components/schemas/AppChargeApproval"},{"description":"The charge an install asks the team to approve, sent back in `approvedCharges`."}]},"description":"The charge a person was shown for each app that charges the team, by app slug: this app and every app the call installs with it, as `charge_approval_required` or the `dependencies_required` plan gave them. Approving it also accepts the developer’s terms. The call is refused with the current charge when an entry is missing, the amount went up or the free days went down since it was shown.","example":{"pixel-sync":{"upToCents":4900,"trialDays":14}}}},"required":["appSlugs"],"description":"The covered apps to install, with the confirmations the operation may require."}}}},"responses":{"200":{"description":"The installs made.","content":{"application/json":{"schema":{"type":"object","properties":{"installed":{"type":"array","items":{"$ref":"#/components/schemas/BundleAppInstall"},"description":"One entry per install made, site by site; empty when every chosen app already ran on every covered site."}},"required":["installed"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"402":{"description":"`no_payment_method` — The team pays by card and has no payment method on file, so nothing was deployed or installed. Add a card on the team’s Billing page, then retry. `team_unpaid` — The team has an unpaid invoice, so it cannot install or enable an app that charges, buy a bundle, or add a site that charges. Nothing changed. Pay what is owed on the team’s Billing page, then retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["no_payment_method","team_unpaid"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"no_payment_method"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`version_not_ready` — The addressed version is still a draft; finalize the push, then retry. `install_changed` — The app installation was removed or replaced while this request was being prepared. Retry to check the current installation and its charges. `version_not_approved` — The site got the app from the app store, so it can run only approved versions. Name another version, or omit the version to get the newest approved one. `version_below_minimum` — Blotout set a minimum version for this app, and the named version is below it. Name the minimum version or a newer one, or omit the version to get the newest one the site may run. `version_not_offered` — Blotout has suspended this app, and the named version was published during the suspension. Name a version published before the suspension, or retry once the suspension is lifted. `cap_reached` — The operation would exceed a site-app capacity limit — either the installed-app count or the worker access-token environment. `message` names the exhausted capacity. `subscription_item_limit` — The team’s Stripe subscription holds the most lines it can, so no further app or bundle that charges can be added to it; `message` names the app or bundle. Nothing was installed or bought. Contact support. `quota_reached` — An object the version declares (a KV namespace, Durable Object class, Pipeline, Hyperdrive config, …) would push the site's host Cloudflare account past its per-account ceiling. `message` names the object type and the account's count; free objects or have the ceiling raised, then retry. `multiple_not_allowed` — The app allows only one install per site, or a version change would leave more installs than the target version allows. `message` states the conflict. `browser_budget` — A version's browser code, or a large value its browser code reads, would push the site's q.js past its size budget; shrink the value, or remove or shrink another app first. `restore_available` — This app was removed from the site recently and can still be brought back with its configuration and data. Call the restore operation to undo the removal, or repeat this call with `replaceRemoved` set to discard it and install a new one. `binding_conflict` — The target version binds a resource name that a version still running on this site binds to something else; `message` names both. Retrying cannot resolve it — the app must use a different binding name, or remove the binding in one version and re-add it in the next. `schema_incompatible` — The site has completed a contract D1 migration that the target app version does not include unchanged; select a schema-compatible version. `variable_retype` — The target version changes a variable’s kind or type while a version still running on this site declares the old shape; `message` names both. Retrying cannot resolve it — the app must use a different variable name, or remove the variable in one version and re-add it in the next. `linked` — The app’s storage is shared through a storage link: a child site binds this site’s objects, or this site binds a parent’s. `message` names the sites; change the link first, or make the change on the parent site. When a child site lacks an app the version needs, `message` names it; install it on that child first. `approval_required` — The target version requests more access than the installed one — API scopes, data buckets, or newly captured query params and cookies; `message` names the additions. Repeat the call with `acceptCapabilities` once a site manager accepts them. `acknowledgement_required` — The app, or an app it needs, declares `necessary` consent, so it runs without visitor consent; `message` names it. Repeat the call with `acknowledgeNecessary` for the app, or with the slug of the app it needs in `acknowledgeNecessaryDependencies`. `dependency_unavailable` — The app needs an app that cannot be installed on this site: it is not in the app store and you are not in its organization, it is suspended or deleted, or it has no version the site may run, or it was removed from this site recently and must be restored or installed on its own first. `message` names it. Nothing was installed. `registry_budget` — The change would grow the site's app configuration past the size the site worker can deploy. Remove an app or an install, or shorten install labels and geo filters, then retry. `message` states the refusal. `app_suspended` — Blotout has suspended this app, so nothing ran and nothing changed. The call works again once the suspension is lifted. `app_taken_down` — Blotout has taken this app down for good, so nothing changed. `message` states what the call cannot do. Do not retry. `purchase_ended` — The bundle purchase that covered the app ended while the install ran, so nothing was installed. Retry: the app then installs at its own price. `removal_pending` — A previous uninstall of this app is torn down as part of this call, and that teardown could not finish — because a deployment for the site is already running, or Cloudflare refused a delete. Nothing was left half-removed and the site's scheduled cleanup carries on, so retry. `sites_paused` — Blotout has paused this team’s sites, so nothing was deployed or installed. Every site of the team answers 410 until the pause ends, and uninstalls, switches and settings changes are still recorded. A payment does not end the pause; contact Blotout. `deploys_blocked` — Blotout has blocked this team’s deploys, so nothing was deployed or installed. The team’s live sites keep running, and uninstalls, switches and settings changes still roll out. A payment does not lift the block; contact Blotout. `charge_approval_required` — The call charges the team and did not approve that charge, or the charge went up, or its free days went down, after it was shown. `charge` holds the current charge and `message` states it. For an app, `appSlug` names the app the charge belongs to: once a person allowed to purchase apps accepts the charge and the developer’s terms, repeat the call with `{ \"<appSlug>\": <charge> }` in `approvedCharges`, keeping the other entries. For a bundle, repeat the call with `charge` as `approvedCharge`. Nothing was installed or bought. `dependencies_required` — The app needs other apps the site does not have yet; `plan` lists every app it needs, at any depth, and whether the site has it. Nothing was installed. Repeat the call with `installDependencies` to install the missing apps first, then the app, and approve the plan’s private-function calls.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["version_not_ready","install_changed","version_not_approved","version_below_minimum","version_not_offered","cap_reached","subscription_item_limit","quota_reached","multiple_not_allowed","browser_budget","restore_available","binding_conflict","schema_incompatible","variable_retype","linked","approval_required","acknowledgement_required","dependency_unavailable","registry_budget","app_suspended","app_taken_down","purchase_ended","removal_pending","sites_paused","deploys_blocked","charge_approval_required","dependencies_required"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"version_not_ready"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"plan":{"$ref":"#/components/schemas/AppDependencyPlan"},"charge":{"$ref":"#/components/schemas/AppChargeApproval"},"appSlug":{"type":"string","description":"With `charge_approval_required`: the app the charge belongs to.","example":"pixel-sync"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/bundle-purchases/{bundlePurchaseId}/cancel":{"post":{"operationId":"cancelBundlePurchase","tags":["Bundle purchases"],"summary":"Cancel a bundle purchase","description":"Cancels a bundle purchase at the end of the period the team has paid for. Nothing is refunded, and until the end the purchase covers its sites and charges as before.\n\n#### How it works\n\n`endedAt` in the response is the first instant the purchase no longer covers: during the bundle’s trial, the day the trial ends, with no charge; otherwise the end of the UTC month for a monthly purchase, the next anniversary for a yearly one, and the end of today for a one-time one. Undo the cancel before then to keep the purchase. At the end, the apps installed under the purchase are disabled with their settings kept, and apps installed before it return to their own price. The caller needs `manage_domain_apps` on every site the purchase covers; a team API token is refused.\n\n#### Required permissions\n\n- `domain:manage_domain_apps:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the purchase, as the list operation returns it.","example":"9c1d2e3f-4a5b-4c6d-8e7f-0a1b2c3d4e5f"},"required":true,"description":"Unique id (UUID) of the purchase, as the list operation returns it.","name":"bundlePurchaseId","in":"path"}],"responses":{"200":{"description":"The cancelled purchase.","content":{"application/json":{"schema":{"type":"object","properties":{"purchase":{"$ref":"#/components/schemas/BundlePurchase"}},"required":["purchase"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`bundle_purchase_cancelled` — The purchase is cancelled already, or has ended. Nothing changed. Undo a cancel before the purchase ends to keep it.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["bundle_purchase_cancelled"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"bundle_purchase_cancelled"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"delete":{"operationId":"undoBundlePurchaseCancel","tags":["Bundle purchases"],"summary":"Undo a purchase cancel","description":"Undoes the team’s cancel of a bundle purchase before it ends, so the purchase stays active with its terms, sites and charges as they were.\n\n#### How it works\n\nThe response has `endedAt` null. A cancel Blotout made cannot be undone. After the end a purchase cannot come back; buy the bundle again instead, with no new trial. The caller needs `manage_domain_apps` on every site the purchase covers; a team API token is refused.\n\n#### Required permissions\n\n- `domain:manage_domain_apps:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the purchase, as the list operation returns it.","example":"9c1d2e3f-4a5b-4c6d-8e7f-0a1b2c3d4e5f"},"required":true,"description":"Unique id (UUID) of the purchase, as the list operation returns it.","name":"bundlePurchaseId","in":"path"}],"responses":{"200":{"description":"The purchase, active again.","content":{"application/json":{"schema":{"type":"object","properties":{"purchase":{"$ref":"#/components/schemas/BundlePurchase"}},"required":["purchase"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"402":{"description":"`team_unpaid` — The team has an unpaid invoice, so it cannot install or enable an app that charges, buy a bundle, or add a site that charges. Nothing changed. Pay what is owed on the team’s Billing page, then retry. `no_payment_method` — The team pays by card and has no payment method on file, so nothing was deployed or installed. Add a card on the team’s Billing page, then retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["team_unpaid","no_payment_method"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"team_unpaid"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`bundle_purchase_not_cancelled` — The purchase is not cancelled, or has ended, so there is no cancel to undo. Nothing changed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["bundle_purchase_not_cancelled"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"bundle_purchase_not_cancelled"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/bundle-purchases/{bundlePurchaseId}/sites/{domainId}":{"put":{"operationId":"addBundlePurchaseSite","tags":["Bundle purchases"],"summary":"Add a site to a purchase","description":"Adds a site to a bundle purchase that has not ended. A site within the purchase’s site limit costs nothing; a site past it costs the extra-site price for each interval. From the next UTC day, the site’s installs of the bundle’s apps charge the bundle’s terms, and the bundle’s other apps can be installed there at no charge.\n\n#### How it works\n\nThe caller needs `manage_domain_apps` on the site; approving a charge also needs `purchase_apps` on the credential and on its user. Extra sites are counted by the peak number of sites the purchase covers on any one UTC day, so swapping one site for another on a later day costs nothing. `charge_approval_required` carries `charge`, the extra-site price per interval; repeat the call with `charge` as `approvedCharge` once a person has accepted it. A purchase whose bundle sells no extra sites answers `bundle_site_limit`; install apps on that site at their own prices. A site the purchase covers already is left as it is. A team API token is refused.\n\n#### Required permissions\n\n- `domain:manage_domain_apps:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the purchase, as the list operation returns it.","example":"9c1d2e3f-4a5b-4c6d-8e7f-0a1b2c3d4e5f"},"required":true,"description":"Unique id (UUID) of the purchase, as the list operation returns it.","name":"bundlePurchaseId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site.","name":"domainId","in":"path"}],"requestBody":{"required":true,"description":"The charge approval for a site past the limit.","content":{"application/json":{"schema":{"type":"object","properties":{"approvedCharge":{"type":"object","properties":{"feeCents":{"type":"integer","minimum":0,"description":"The most the call charges per interval, in US cents: for a purchase, the price plus the extra sites past the limit; for an added site, the extra-site price.","example":3900},"monthlyUsageCapCents":{"type":"integer","minimum":0,"description":"The most the bundle’s usage can charge in one month, in US cents, whatever the interval; 0 when it has no usage cap.","example":2000},"interval":{"type":"string","enum":["monthly","yearly","one_time"],"description":"The interval the fee is per.","example":"monthly"},"trialDays":{"type":"integer","minimum":0,"description":"The free days before the first charge; 0 when the bundle has no trial or it is over.","example":14}},"required":["feeCents","monthlyUsageCapCents","interval","trialDays"],"description":"The charge a person was shown, sent back as `charge_approval_required` gave it. Needed when the call charges. The call answers `charge_approval_required` with the current charge when it is missing, the fee or usage cap went up, the free days went down or the interval changed since it was shown.","example":{"feeCents":3900,"monthlyUsageCapCents":2000,"interval":"monthly","trialDays":14}}},"description":"The charge approval for a site past the limit; send `{}` for a site within it."}}}},"responses":{"200":{"description":"The purchase with the site.","content":{"application/json":{"schema":{"type":"object","properties":{"purchase":{"$ref":"#/components/schemas/BundlePurchase"}},"required":["purchase"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"402":{"description":"`team_unpaid` — The team has an unpaid invoice, so it cannot install or enable an app that charges, buy a bundle, or add a site that charges. Nothing changed. Pay what is owed on the team’s Billing page, then retry. `no_payment_method` — The team pays by card and has no payment method on file, so nothing was deployed or installed. Add a card on the team’s Billing page, then retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["team_unpaid","no_payment_method"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"team_unpaid"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`bundle_purchase_cancelled` — The purchase is cancelled already, or has ended. Nothing changed. Undo a cancel before the purchase ends to keep it. `bundle_site_limit` — The sites exceed the bundle’s site limit and the bundle sells no extra sites. Nothing changed. Choose fewer sites; the other sites install apps at the apps’ own prices. `charge_approval_required` — The call charges the team and did not approve that charge, or the charge went up, or its free days went down, after it was shown. `charge` holds the current charge and `message` states it. For an app, `appSlug` names the app the charge belongs to: once a person allowed to purchase apps accepts the charge and the developer’s terms, repeat the call with `{ \"<appSlug>\": <charge> }` in `approvedCharges`, keeping the other entries. For a bundle, repeat the call with `charge` as `approvedCharge`. Nothing was installed or bought.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["bundle_purchase_cancelled","bundle_site_limit","charge_approval_required"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"bundle_purchase_cancelled"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"charge":{"$ref":"#/components/schemas/BundleChargeApproval"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"delete":{"operationId":"removeBundlePurchaseSite","tags":["Bundle purchases"],"summary":"Remove a site from a purchase","description":"Removes a site from a bundle purchase that has not ended. Nothing is refunded: an extra site already charged for its period stays charged.\n\n#### How it works\n\nThe site’s apps installed before the purchase return to their own price at once, and the apps installed under the purchase are disabled with their settings kept, as at the end of the purchase. The last site can be removed too, so a purchase for one site can swap it on a later day at no charge; the purchase charges until it is cancelled. The caller needs `manage_domain_apps` on the site; a team API token is refused.\n\n#### Required permissions\n\n- `domain:manage_domain_apps:write` on all domains, or on the addressed domain when its id is in the route","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the purchase, as the list operation returns it.","example":"9c1d2e3f-4a5b-4c6d-8e7f-0a1b2c3d4e5f"},"required":true,"description":"Unique id (UUID) of the purchase, as the list operation returns it.","name":"bundlePurchaseId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site.","name":"domainId","in":"path"}],"responses":{"200":{"description":"The purchase without the site.","content":{"application/json":{"schema":{"type":"object","properties":{"purchase":{"$ref":"#/components/schemas/BundlePurchase"}},"required":["purchase"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`bundle_purchase_cancelled` — The purchase is cancelled already, or has ended. Nothing changed. Undo a cancel before the purchase ends to keep it.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["bundle_purchase_cancelled"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"bundle_purchase_cancelled"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/storage-links":{"get":{"operationId":"listStorageLinks","tags":["Storage links"],"summary":"List storage links","description":"Lists the team’s storage link configurations newest first, each with its parent site and how many sites share that parent’s storage.\n\n#### How it works\n\nPage with `cursorAt` and `cursorId` from the previous response’s `nextCursor`; a null cursor means the last page.\n\n#### Required permissions\n\n- `team:manage_storage_links:read` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many configurations to return, 1–200.","example":50},"required":false,"description":"How many configurations to return, 1–200.","name":"limit","in":"query"},{"schema":{"type":"string","format":"date-time","description":"Continue after this configuration’s creation instant, from a previous response’s cursor.","example":"2026-09-21T10:04:31.000Z"},"required":false,"description":"Continue after this configuration’s creation instant, from a previous response’s cursor.","name":"cursorAt","in":"query"},{"schema":{"type":"string","description":"Continue after this configuration’s id, from a previous response’s cursor. Send it with `cursorAt`.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"required":false,"description":"Continue after this configuration’s id, from a previous response’s cursor. Send it with `cursorAt`.","name":"cursorId","in":"query"}],"responses":{"200":{"description":"The page of configurations.","content":{"application/json":{"schema":{"type":"object","properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/StorageLinkSummary"},"description":"The page of configurations, newest first."},"nextCursor":{"type":["object","null"],"properties":{"at":{"type":"string","description":"Pass as `cursorAt`.","example":"2026-09-21T10:04:31.000Z"},"id":{"type":"string","description":"Pass as `cursorId`.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"}},"required":["at","id"],"description":"Where the next page starts, or null on the last one."}},"required":["records","nextCursor"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"post":{"operationId":"createStorageLink","tags":["Storage links"],"summary":"Create a storage link","description":"Creates a storage link configuration around one parent site. Add child sites afterwards and choose per child what they share.\n\n#### How it works\n\nThe parent must be deployed and in no other configuration, or the call fails with `not_eligible`; a name the team already uses fails with `name_taken`. Nothing is deployed by this call.\n\n#### Required permissions\n\n- `team:manage_storage_links:write` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"}],"requestBody":{"required":true,"description":"The name and the parent site.","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Name of the configuration, unique within the team, up to 100 characters.","example":"EU markets"},"parentDomainId":{"type":"string","format":"uuid","description":"The site whose storage the children will share.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"}},"required":["name","parentDomainId"]}}}},"responses":{"201":{"description":"The configuration was created.","content":{"application/json":{"schema":{"type":"object","properties":{"storageLinkId":{"type":"string","description":"Id of the new configuration.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"}},"required":["storageLinkId"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`not_eligible` — The site cannot join this configuration: it is not deployed, is on another host or jurisdiction than the parent, or still binds storage from an earlier link. `message` states which. `name_taken` — The team already has a storage link configuration with this name; choose another. `already_linked` — The site already belongs to a storage link configuration, as parent or child; a site is in at most one. Remove it there first.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_eligible","name_taken","already_linked"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_eligible"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/storage-links/{storageLinkId}":{"get":{"operationId":"getStorageLink","tags":["Storage links"],"summary":"Get a storage link","description":"Returns one configuration: its parent, every child with what it shares, what each child set aside, and whether each site has caught up.\n\n#### How it works\n\nA child with `sync.pending` still has a deployment to land; `nextSyncAttemptAt` says when a failed one is retried. A removed child stays listed by its `liveAliases` and `reverseBindingLive` until both clear.\n\n#### Required permissions\n\n- `team:manage_storage_links:read` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the storage link configuration.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"description":"Unique id (UUID) of the storage link configuration.","name":"storageLinkId","in":"path"}],"responses":{"200":{"description":"The configuration.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorageLink"}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"patch":{"operationId":"renameStorageLink","tags":["Storage links"],"summary":"Rename a storage link","description":"Renames a configuration. A name the team already uses fails with `name_taken`; nothing else about the configuration changes.\n\n#### Required permissions\n\n- `team:manage_storage_links:write` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the storage link configuration.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"description":"Unique id (UUID) of the storage link configuration.","name":"storageLinkId","in":"path"}],"requestBody":{"required":true,"description":"The new name.","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Name of the configuration, unique within the team, up to 100 characters.","example":"EU markets"}},"required":["name"]}}}},"responses":{"200":{"description":"The stored name.","content":{"application/json":{"schema":{"type":"object","properties":{"storageLinkId":{"type":"string","description":"Id of the configuration.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"name":{"type":"string","description":"The stored name.","example":"EU markets"}},"required":["storageLinkId","name"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`name_taken` — The team already has a storage link configuration with this name; choose another.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["name_taken"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"name_taken"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"delete":{"operationId":"deleteStorageLink","tags":["Storage links"],"summary":"Delete a storage link","description":"Deletes a configuration and unlinks every child at once: each child flips back to its own storage, with the data it set aside when it was linked.\n\n#### How it works\n\nThe change is saved before any site is redeployed. `redeploy.redeployed` says whether every affected site was redeployed immediately; otherwise `redeploy.reason` explains and the sync retries on its own.\n\n#### Required permissions\n\n- `team:manage_storage_links:write` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the storage link configuration.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"description":"Unique id (UUID) of the storage link configuration.","name":"storageLinkId","in":"path"}],"responses":{"200":{"description":"The configuration was deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"unlinked":{"type":"array","items":{"type":"object","properties":{"domainId":{"type":"string","description":"Id of the site that flips back to its own storage.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"domain":{"type":"string","description":"Its hostname.","example":"de.example.com"}},"required":["domainId","domain"]},"description":"The children that were unlinked."},"redeploy":{"$ref":"#/components/schemas/StorageLinkRedeploy"}},"required":["unlinked","redeploy"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/storage-links/{storageLinkId}/eligible-sites":{"get":{"operationId":"listStorageLinkEligibleSites","tags":["Storage links"],"summary":"List eligible sites","description":"Lists the sites that can be added to the configuration as children: on the parent’s host and jurisdiction, deployed, and in no configuration. The list is empty until the parent is deployed.\n\n#### Required permissions\n\n- `team:manage_storage_links:read` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the storage link configuration.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"description":"Unique id (UUID) of the storage link configuration.","name":"storageLinkId","in":"path"}],"responses":{"200":{"description":"The eligible sites.","content":{"application/json":{"schema":{"type":"object","properties":{"sites":{"type":"array","items":{"type":"object","properties":{"domainId":{"type":"string","description":"Id of the site.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"domain":{"type":"string","description":"Its hostname.","example":"de.example.com"}},"required":["domainId","domain"]},"description":"Sites that can be added as children, sorted by hostname."}},"required":["sites"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/storage-links/{storageLinkId}/children":{"post":{"operationId":"addStorageLinkChild","tags":["Storage links"],"summary":"Add a child site","description":"Adds a site to the configuration as a child. Nothing is shared yet: set the child’s resources afterwards to choose what it takes from the parent.\n\n#### How it works\n\nEligibility is checked again at write time, so a site that stopped being eligible after you listed it fails with `not_eligible`; a site already in a configuration fails with `already_linked`.\n\n#### Required permissions\n\n- `team:manage_storage_links:write` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the storage link configuration.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"description":"Unique id (UUID) of the storage link configuration.","name":"storageLinkId","in":"path"}],"requestBody":{"required":true,"description":"The site to add.","content":{"application/json":{"schema":{"type":"object","properties":{"domainId":{"type":"string","format":"uuid","description":"The site to add as a child; it must be eligible.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"}},"required":["domainId"]}}}},"responses":{"201":{"description":"The site was added.","content":{"application/json":{"schema":{"type":"object","properties":{"domainId":{"type":"string","description":"Id of the site that was added.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"}},"required":["domainId"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`not_eligible` — The site cannot join this configuration: it is not deployed, is on another host or jurisdiction than the parent, or still binds storage from an earlier link. `message` states which. `already_linked` — The site already belongs to a storage link configuration, as parent or child; a site is in at most one. Remove it there first.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_eligible","already_linked"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_eligible"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/storage-links/{storageLinkId}/children/{domainId}":{"delete":{"operationId":"removeStorageLinkChild","tags":["Storage links"],"summary":"Remove a child site","description":"Removes a child from the configuration. The site flips back to its own storage, with the data it set aside when it was linked.\n\n#### How it works\n\nThe change is saved before any site is redeployed; `redeploy` reports whether the immediate redeploys landed, and the sync retries any that did not. The site cannot be deleted or added elsewhere until it has been redeployed.\n\n#### Required permissions\n\n- `team:manage_storage_links:write` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the storage link configuration.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"description":"Unique id (UUID) of the storage link configuration.","name":"storageLinkId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the child site.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the child site.","name":"domainId","in":"path"}],"responses":{"200":{"description":"The child was removed.","content":{"application/json":{"schema":{"type":"object","properties":{"redeploy":{"$ref":"#/components/schemas/StorageLinkRedeploy"}},"required":["redeploy"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/storage-links/{storageLinkId}/children/{domainId}/shareable":{"get":{"operationId":"listStorageLinkShareable","tags":["Storage links"],"summary":"List shareable storage","description":"Lists what a child could share from the parent: the identity graph as one item, and per installed app the storage it declares, each with whether the parent can satisfy it now and why not.\n\n#### How it works\n\nAn item is available only when both sites are deployed and, for an app, both run the same fully deployed version and the parent has the object. The site’s own analytics datasets are never offered.\n\n#### Required permissions\n\n- `team:manage_storage_links:read` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the storage link configuration.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"description":"Unique id (UUID) of the storage link configuration.","name":"storageLinkId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the child site.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the child site.","name":"domainId","in":"path"}],"responses":{"200":{"description":"The shareable storage.","content":{"application/json":{"schema":{"type":"object","properties":{"identityGraph":{"type":"object","properties":{"available":{"type":"boolean","description":"Whether the parent can satisfy it now.","example":true},"reason":{"type":["string","null"],"enum":["child_not_deployed","child_not_converged","parent_not_deployed","parent_missing_app","parent_not_converged","version_mismatch","parent_resource_missing",null],"description":"Why it cannot be shared yet, or null when it can.","example":null}},"required":["available","reason"],"description":"Whether the identity graph can be shared as a whole."},"apps":{"type":"array","items":{"type":"object","properties":{"appId":{"type":"string","description":"Id of the app installed on the child.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"appSlug":{"type":"string","description":"Its slug.","example":"facebook-capi"},"appName":{"type":"string","description":"Its name.","example":"Facebook CAPI"},"version":{"type":"string","description":"The version the child runs.","example":"1.4.0"},"resources":{"type":"array","items":{"type":"object","properties":{"identifier":{"type":"string","description":"The resource identifier.","example":"cache"},"type":{"type":"string","enum":["kv","d1","r2","analytics_engine","vectorize","durable_object"],"description":"The kind of storage object.","example":"kv"},"available":{"type":"boolean","description":"Whether the parent can satisfy it now.","example":true},"reason":{"type":["string","null"],"enum":["child_not_deployed","child_not_converged","parent_not_deployed","parent_missing_app","parent_not_converged","version_mismatch","parent_resource_missing",null],"description":"Why it cannot be shared yet, or null when it can.","example":null}},"required":["identifier","type","available","reason"]},"description":"The storage that app declares, with whether each item can be shared."}},"required":["appId","appSlug","appName","version","resources"]},"description":"The child’s installed apps, sorted by slug."}},"required":["identityGraph","apps"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/storage-links/{storageLinkId}/children/{domainId}/resources":{"put":{"operationId":"setStorageLinkResources","tags":["Storage links"],"summary":"Set shared storage","description":"Replaces what a child shares from the parent. Send the complete set: anything omitted flips back to the child’s own storage, and anything added sets the child’s own object aside until it is unlinked.\n\n#### How it works\n\nThe identity graph is shared as a whole — the three `appId: null` rows `anon`, `global` and `alias` together, or `partial_identity_graph` is returned. Any other site-level row, a resource the child does not declare, or one the parent cannot satisfy yet fails with `not_shareable`. `redeploy` reports whether the immediate redeploys landed; the sync retries any that did not.\n\n#### Required permissions\n\n- `team:manage_storage_links:write` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the storage link configuration.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"description":"Unique id (UUID) of the storage link configuration.","name":"storageLinkId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the child site.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the child site.","name":"domainId","in":"path"}],"requestBody":{"required":true,"description":"The complete selection.","content":{"application/json":{"schema":{"type":"object","properties":{"resources":{"type":"array","items":{"type":"object","properties":{"appId":{"type":["string","null"],"format":"uuid","description":"The app that declares the resource, or null for the site’s identity graph.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"identifier":{"type":"string","minLength":1,"description":"The resource identifier from the app manifest, or `anon`, `global`, `alias` for the identity graph.","example":"cache"},"type":{"type":"string","enum":["kv","d1","r2","analytics_engine","vectorize","durable_object"],"description":"The kind of storage object.","example":"kv"}},"required":["appId","identifier","type"]},"maxItems":500,"description":"The complete set the child shares from the parent. The identity graph is the three `appId: null` rows `anon`, `global` and `alias` together."}},"required":["resources"]}}}},"responses":{"200":{"description":"The selection was saved.","content":{"application/json":{"schema":{"type":"object","properties":{"changed":{"type":"boolean","description":"Whether the selection differed from what was stored.","example":true},"redeploy":{"$ref":"#/components/schemas/StorageLinkRedeploy"}},"required":["changed","redeploy"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"422":{"description":"`partial_identity_graph` — The identity graph is shared as a whole; send the three `appId: null` rows `anon`, `global` and `alias` together, or none of them. `not_shareable` — A selected resource cannot be shared: it is a site-level object other than the identity graph, the child does not declare it, or the parent cannot satisfy it yet. `message` names it.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["partial_identity_graph","not_shareable"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"partial_identity_graph"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/teams/{teamId}/storage-links/{storageLinkId}/children/{domainId}/discard":{"post":{"operationId":"discardStorageLinkParked","tags":["Storage links"],"summary":"Discard parked storage","description":"Deletes the app storage a child set aside when it started sharing the parent’s: its own KV, D1, R2 and Vectorize objects. Unlinking afterwards gives the child fresh, empty objects.\n\n#### How it works\n\nAnalytics data cannot be deleted and ages out after Cloudflare’s retention period. The identity graph is kept and comes back if the child is unlinked. The deletion is recorded before any object is removed; `remaining` counts objects the sync still has to delete.\n\n#### Required permissions\n\n- `team:manage_storage_links:write` on the team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":true,"description":"Unique id (UUID) of the team that owns the addressed resources, as shown in the team settings on the Blotout platform.","name":"teamId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the storage link configuration.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"description":"Unique id (UUID) of the storage link configuration.","name":"storageLinkId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the child site.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the child site.","name":"domainId","in":"path"}],"responses":{"200":{"description":"What was discarded.","content":{"application/json":{"schema":{"type":"object","properties":{"discarded":{"type":"array","items":{"type":"object","properties":{"appId":{"type":"string","description":"The app that declares the resource.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"appSlug":{"type":"string","description":"That app’s slug.","example":"facebook-capi"},"identifier":{"type":"string","description":"The resource identifier.","example":"cache"},"type":{"type":"string","enum":["kv","d1","r2","analytics_engine","vectorize","durable_object"],"description":"The kind of storage object.","example":"kv"}},"required":["appId","appSlug","identifier","type"]},"description":"The parked app storage that was deleted."},"remaining":{"type":"integer","description":"How many objects the sync still has to delete.","example":0}},"required":["discarded","remaining"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/oauth/token":{"post":{"operationId":"createOauthToken","tags":["OAuth"],"summary":"Exchange or refresh a token","description":"Issues `qoa_` access tokens: exchanges a one-time authorization code from the consent flow, rotates a `qor_` refresh token into its successor plus a fresh access token, or re-audiences a token for another Qinto resource server (RFC 8693).\n\n#### How it works\n\nRequests are form-encoded per RFC 6749. Confidential clients authenticate with HTTP Basic or `client_secret_post`; public clients send their `client_id` alone. `resource` is single-valued — every access token is bound to exactly one audience — and a replayed code or reused refresh token revokes the whole grant. A token exchange takes `subject_token` and `subject_token_type`, carries the subject’s teams and scope across unchanged, never outlives it, and answers `429` when the session’s exchange budget is exhausted. Responses carry `Cache-Control: no-store`.","security":[],"requestBody":{"required":true,"description":"RFC 6749 form-encoded token request.","content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"grant_type":{"type":"string","description":"The grant type: `authorization_code` to redeem a consent code, `refresh_token` to rotate a refresh token, or `urn:ietf:params:oauth:grant-type:token-exchange` for the RFC 8693 exchange.","example":"authorization_code"},"code":{"type":"string","description":"The one-time `qac_` authorization code from the consent redirect. Required for `authorization_code`.","example":"qac_9f2c…"},"redirect_uri":{"type":"string","description":"The exact redirect URI used in the authorization request. Required for `authorization_code`.","example":"https://example.com/callback"},"client_id":{"type":"string","description":"The app’s client id. Required unless the client authenticates with HTTP Basic.","example":"qc_4b1d…"},"client_secret":{"type":"string","description":"The app’s client secret for `client_secret_post` authentication. Public clients omit it.","example":"qcs_71aa…"},"code_verifier":{"type":"string","description":"The PKCE code verifier whose S256 digest was sent as the authorization request’s code challenge. Required for `authorization_code`.","example":"dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"},"refresh_token":{"type":"string","description":"The current `qor_` refresh token to rotate. Required for `refresh_token`.","example":"qor_5e0b…"},"scope":{"type":"string","description":"Optional narrowing scope for `refresh_token`: a space-delimited subset of the grant’s scope.","example":"team:read"},"resource":{"type":"string","description":"Optional RFC 8707 resource the token is minted for. Single-valued: every access token is bound to exactly one audience.","example":"https://qinto-api.blotout.io"},"subject_token":{"type":"string","description":"The `qoa_` access token to re-audience. Required for `urn:ietf:params:oauth:grant-type:token-exchange`.","example":"qoa_83fe…"},"subject_token_type":{"type":"string","description":"The type of `subject_token`, required by RFC 8693 §2.1 for the exchange. Only `urn:ietf:params:oauth:token-type:access_token` is accepted.","example":"urn:ietf:params:oauth:token-type:access_token"},"requested_token_type":{"type":"string","description":"The type of token to issue. Optional; only `urn:ietf:params:oauth:token-type:access_token` is accepted.","example":"urn:ietf:params:oauth:token-type:access_token"}},"required":["grant_type"]}}}},"responses":{"200":{"description":"The issued tokens.","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string","description":"The issued `qoa_` bearer token, valid for `expires_in` seconds at exactly one resource server.","example":"qoa_83fe…"},"token_type":{"type":"string","enum":["bearer"],"description":"Always `bearer`.","example":"bearer"},"expires_in":{"type":"number","description":"Access-token lifetime in seconds.","example":3600},"refresh_token":{"type":"string","description":"The new `qor_` refresh token. Present when the grant carries `offline_access`; each use rotates it, so store this one and discard its predecessor.","example":"qor_5e0b…"},"scope":{"type":"string","description":"The scope actually granted (RFC 6749 §5.1), which may be narrower than requested.","example":"team:read offline_access"},"issued_token_type":{"type":"string","description":"The type of the issued token. Present on a token exchange, where RFC 8693 §2.2.1 requires it.","example":"urn:ietf:params:oauth:token-type:access_token"}},"required":["access_token","token_type","expires_in","scope"]}}}},"400":{"description":"The request failed: `invalid_request`, `invalid_grant`, `unsupported_grant_type`, `invalid_scope`, or `invalid_target`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_request","invalid_client","invalid_grant","unsupported_grant_type","invalid_scope","invalid_target"],"description":"The RFC 6749 / RFC 8707 error code.","example":"invalid_grant"},"error_description":{"type":"string","description":"A human-readable explanation of the failure, safe to log.","example":"The authorization code has expired."}},"required":["error"]}}}},"401":{"description":"`invalid_client` — client authentication failed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_request","invalid_client","invalid_grant","unsupported_grant_type","invalid_scope","invalid_target"],"description":"The RFC 6749 / RFC 8707 error code.","example":"invalid_grant"},"error_description":{"type":"string","description":"A human-readable explanation of the failure, safe to log.","example":"The authorization code has expired."}},"required":["error"]}}}},"429":{"description":"The token-exchange budget for this session is exhausted; retry shortly.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_request","invalid_client","invalid_grant","unsupported_grant_type","invalid_scope","invalid_target"],"description":"The RFC 6749 / RFC 8707 error code.","example":"invalid_grant"},"error_description":{"type":"string","description":"A human-readable explanation of the failure, safe to log.","example":"The authorization code has expired."}},"required":["error"]}}}}}}},"/oauth/revoke":{"post":{"operationId":"revokeOauthToken","tags":["OAuth"],"summary":"Revoke a token","description":"Revokes a `qoa_` access token, or a `qor_` refresh token together with its whole grant, per RFC 7009.\n\n#### How it works\n\nClient authentication follows the same rules as the token endpoint. The response is 200 whether or not the token matched: an unknown token, or a token issued to a different app, is silently ignored so the endpoint cannot be used as a validity oracle.","security":[],"requestBody":{"required":true,"description":"RFC 7009 form-encoded revocation request.","content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"token":{"type":"string","description":"The `qoa_` access token or `qor_` refresh token to revoke. Revoking a refresh token revokes its whole grant.","example":"qor_5e0b…"},"token_type_hint":{"type":"string","description":"Optional RFC 7009 hint (`access_token` or `refresh_token`); the token prefix already decides, so it is ignored.","example":"refresh_token"},"client_id":{"type":"string","description":"The app’s client id. Required unless the client authenticates with HTTP Basic.","example":"qc_4b1d…"},"client_secret":{"type":"string","description":"The app’s client secret for `client_secret_post` authentication. Public clients omit it.","example":"qcs_71aa…"}},"required":["token"]}}}},"responses":{"200":{"description":"The request was processed; any matching token is revoked.","content":{"application/json":{"schema":{"type":"object","properties":{"revoked":{"type":"boolean","enum":[true],"description":"Always `true`: the request was processed. Unknown tokens and other apps’ tokens are ignored without an error.","example":true}},"required":["revoked"]}}}},"400":{"description":"`invalid_request` — the request body is malformed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_request","invalid_client","invalid_grant","unsupported_grant_type","invalid_scope","invalid_target"],"description":"The RFC 6749 / RFC 8707 error code.","example":"invalid_grant"},"error_description":{"type":"string","description":"A human-readable explanation of the failure, safe to log.","example":"The authorization code has expired."}},"required":["error"]}}}},"401":{"description":"`invalid_client` — client authentication failed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_request","invalid_client","invalid_grant","unsupported_grant_type","invalid_scope","invalid_target"],"description":"The RFC 6749 / RFC 8707 error code.","example":"invalid_grant"},"error_description":{"type":"string","description":"A human-readable explanation of the failure, safe to log.","example":"The authorization code has expired."}},"required":["error"]}}}}}}},"/.well-known/oauth-authorization-server":{"get":{"operationId":"getOauthServerMetadata","tags":["OAuth"],"summary":"Discover the OAuth server","description":"Serves the RFC 8414 authorization-server metadata document OAuth and MCP clients use to discover the endpoints, PKCE requirement, and supported scopes.\n\n#### How it works\n\nThe document is public and CORS-enabled so browser-based clients can fetch it cross-origin. The issuer is this API’s origin; the authorization endpoint lives on the Blotout platform origin, where the consent screen renders.","security":[],"responses":{"200":{"description":"The RFC 8414 metadata document.","content":{"application/json":{"schema":{"type":"object","properties":{"issuer":{"type":"string","description":"The authorization server’s issuer identifier: this API’s origin.","example":"https://qinto-api.blotout.io"},"authorization_endpoint":{"type":"string","description":"Where user-facing authorization requests go — the consent screen on the Blotout platform.","example":"https://platform.blotout.io/oauth/authorize"},"token_endpoint":{"type":"string","description":"The token endpoint on this API.","example":"https://qinto-api.blotout.io/oauth/token"},"revocation_endpoint":{"type":"string","description":"The RFC 7009 revocation endpoint on this API.","example":"https://qinto-api.blotout.io/oauth/revoke"},"grant_types_supported":{"type":"array","items":{"type":"string"},"description":"The supported grant types.","example":["authorization_code","refresh_token"]},"response_types_supported":{"type":"array","items":{"type":"string"},"description":"The supported response types.","example":["code"]},"response_modes_supported":{"type":"array","items":{"type":"string"},"description":"The supported response modes.","example":["query"]},"code_challenge_methods_supported":{"type":"array","items":{"type":"string"},"description":"The supported PKCE code-challenge methods; PKCE is mandatory.","example":["S256"]},"token_endpoint_auth_methods_supported":{"type":"array","items":{"type":"string"},"description":"The client-authentication methods the token endpoint accepts.","example":["client_secret_basic","client_secret_post","none"]},"revocation_endpoint_auth_methods_supported":{"type":"array","items":{"type":"string"},"description":"The client-authentication methods the revocation endpoint accepts.","example":["client_secret_basic","client_secret_post","none"]},"client_id_metadata_document_supported":{"type":"boolean","enum":[true],"description":"Always `true`: clients may identify themselves with an HTTPS client-id metadata document (CIMD).","example":true},"scopes_supported":{"type":"array","items":{"type":"string"},"description":"Every scope token the grammar accepts, including `offline_access`, except `bundles`: an MCP client learns that one from the MCP server.","example":["team:read","domain:read","offline_access"]}},"required":["issuer","authorization_endpoint","token_endpoint","revocation_endpoint","grant_types_supported","response_types_supported","response_modes_supported","code_challenge_methods_supported","token_endpoint_auth_methods_supported","revocation_endpoint_auth_methods_supported","client_id_metadata_document_supported","scopes_supported"]}}}}}}},"/me":{"get":{"operationId":"getMe","tags":["User"],"summary":"Get the calling identity","description":"Returns who is calling: the identity behind the presented token, the teams it may access, and the access it carries. Call it to confirm a credential works and to discover the `teamId` other operations need.\n\n#### How it works\n\nA team API token identifies only itself and its one team. A user-authorized OAuth token reports each team selected during consent. `user` is filled only when that grant includes the `profile` scope, and `organizations` when it includes `profile`, `developer` or `bundles`.\n\n#### Required permissions\n\n- None beyond a valid token; `user` additionally requires the `profile` scope on the token’s grant, and `organizations` the `profile`, `developer` or `bundles` scope","security":[{"QintoAccessToken":[]}],"responses":{"200":{"description":"The identity behind the presented token.","content":{"application/json":{"schema":{"type":"object","properties":{"tokenType":{"type":"string","enum":["oauth","api_token"],"description":"How the caller authenticated: a user-authorized OAuth token or a team API token.","example":"oauth"},"name":{"type":"string","description":"For an OAuth token, the authorized app’s name; for a team API token, the token’s own name.","example":"Qinto CLI"},"user":{"$ref":"#/components/schemas/MeUser"},"teams":{"type":"array","items":{"$ref":"#/components/schemas/MeTeamMembership"},"description":"Every team this credential may access, with its independently granted scope."},"organizations":{"type":"array","items":{"$ref":"#/components/schemas/MeOrganization"},"description":"Every developer organization the authorizing user belongs to; empty without the `profile`, `developer` or `bundles` scope and for team API tokens."},"scopes":{"type":"array","items":{"type":"string","description":"A scope token from the Qinto scope grammar.","example":"team:write"},"description":"The presented token’s access as scope tokens: an OAuth token’s granted scope, or a team API token’s policies expressed as scopes."}},"required":["tokenType","name","user","teams","organizations","scopes"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/me/app-tools":{"get":{"operationId":"listCallerAppTools","tags":["User"],"summary":"List reachable app tools","description":"Lists every tool the caller can run, contributed by the apps installed on the sites they may read — one entry per app tool, whichever sites it reaches. Apps the caller has no access to, and tools above their app role on a site, are left out.\n\n#### How it works\n\nA tool is listed only when every site the caller can run it on agrees on the arguments it takes, so one advertised schema is always the right one. Anything else left out appears in `warnings` with the sites and versions involved. Requires an OAuth access token.\n\n#### Required permissions\n\n- None beyond a valid token; each tool additionally needs read access to the site it is listed for","security":[{"QintoAccessToken":[]}],"responses":{"200":{"description":"The reachable tools.","content":{"application/json":{"schema":{"type":"object","properties":{"tools":{"type":"array","items":{"$ref":"#/components/schemas/CallerAppTool"},"description":"The reachable tools, ordered by app slug then tool name."},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/CallerAppToolWarning"},"description":"Tools deliberately left out of `tools`, so a staggered rollout is never silent."}},"required":["tools","warnings"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/me/installable-apps":{"get":{"operationId":"listInstallableApps","tags":["User"],"summary":"List installable apps","description":"Lists the apps the caller may install on a site: every published app of each developer organization they belong to, with its latest version. Call it to find the `appSlug` an install takes.\n\n#### How it works\n\nApps with no published version are left out. Page with `cursor` from the previous response’s `nextCursor`; a null cursor means the last page. Installing still needs app management on the target site.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `profile` scope, and installing a listed app additionally needs `domain:manage_domain_apps:write` on the target site","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many apps to return, 1–200.","example":50},"required":false,"description":"How many apps to return, 1–200.","name":"limit","in":"query"},{"schema":{"type":"string","description":"Continue after this app slug, from a previous response’s `nextCursor`.","example":"facebook-capi"},"required":false,"description":"Continue after this app slug, from a previous response’s `nextCursor`.","name":"cursor","in":"query"}],"responses":{"200":{"description":"The page of apps.","content":{"application/json":{"schema":{"type":"object","properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/InstallableApp"},"description":"The page of apps, A–Z by slug."},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page, or null on the last one.","example":"facebook-capi"}},"required":["records","nextCursor"]}}}},"400":{"description":"`invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_body"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/developer/app-slugs/{slug}":{"get":{"operationId":"checkAppSlug","tags":["Developer apps"],"summary":"Check an app slug","description":"Reports whether a slug is still free, and offers free alternatives when it is not, so a developer can pick another one before the app is built around it. The slug namespace is global: it spans every organization.\n\n#### How it works\n\nAn unavailable answer is final — `taken` slugs stay reserved even after the app is deleted, and `reserved` ones belong to the Blotout platform — and carries up to three free variations of the slug in `suggestions`. An available answer can still lose a race with another registration, so the create operation stays authoritative and can answer `slug_taken` afterwards.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` scope","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{1,28}[a-z0-9]$","description":"The slug to check: 3-30 lowercase letters, digits, and hyphens, starting with a letter and not ending with a hyphen.","example":"facebook-capi"},"required":true,"description":"The slug to check: 3-30 lowercase letters, digits, and hyphens, starting with a letter and not ending with a hyphen.","name":"slug","in":"path"}],"responses":{"200":{"description":"The slug was checked; `available` carries the verdict, `reason` says why an unavailable slug is refused, and `suggestions` lists free slugs to offer instead.","content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string","description":"The slug that was checked.","example":"facebook-capi"},"available":{"type":"boolean","description":"Whether the slug can still be registered. False means the create operation would refuse it.","example":true},"reason":{"type":["string","null"],"enum":["taken","reserved",null],"description":"Why the slug is unavailable: `taken` when an app already claimed it, `reserved` when the Blotout platform keeps it for its own surfaces. Null when the slug is available.","example":"taken"},"suggestions":{"type":"array","items":{"type":"string","description":"A free variation of the requested slug.","example":"facebook-capi-labs"},"description":"Up to three free slugs to offer instead, worded from the requested one and ordered at random. Empty when the requested slug is available."}},"required":["slug","available","reason","suggestions"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/developer/organizations/{organizationId}/apps":{"get":{"operationId":"listApps","tags":["Developer apps"],"summary":"List apps","description":"Lists one page of the organization’s apps, newest first. Call it to discover the `appId` and `slug` the other app operations reference.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` scope, for a user who belongs to the addressed organization","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"date-time","description":"The `nextCursor.createdAt` of the previous page.","example":"2026-08-30T12:00:00.000Z"},"required":false,"description":"The `nextCursor.createdAt` of the previous page.","name":"cursorCreatedAt","in":"query"},{"schema":{"type":"string","description":"The `nextCursor.id` of the previous page.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":false,"description":"The `nextCursor.id` of the previous page.","name":"cursorId","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"description":"Page size, 1–200 (default 50).","example":50},"required":false,"description":"Page size, 1–200 (default 50).","name":"limit","in":"query"}],"responses":{"200":{"description":"The organization’s apps.","content":{"application/json":{"schema":{"type":"object","properties":{"apps":{"type":"array","items":{"$ref":"#/components/schemas/App"},"description":"One page of the organization’s apps, newest first."},"nextCursor":{"type":["object","null"],"properties":{"createdAt":{"type":"string","description":"Creation instant of the last listed app.","example":"2026-08-30T12:00:00.000Z"},"id":{"type":"string","description":"Id of the last listed app.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"}},"required":["createdAt","id"],"description":"Pass both fields as `cursorCreatedAt` / `cursorId` for the next page; `null` on the last page."}},"required":["apps","nextCursor"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"post":{"operationId":"createApp","tags":["Developer apps"],"summary":"Create an app","description":"Registers an app under the organization. The returned `appId` is what the other app operations reference; the `slug` is the identity the app runs under on every site.\n\n#### How it works\n\nThe slug is fixed at creation and can never be changed or reused: it stays reserved even after the app is deleted, so `slug_taken` can name an app that no longer exists. The name and description stay editable.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` scope, for an owner or developer of the addressed organization","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"}],"requestBody":{"required":true,"description":"The new app’s slug, name, and optional description.","content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$","description":"3-30 lowercase letters, digits, and hyphens, starting with a letter and not ending with a hyphen. Immutable and globally unique; once used it stays reserved forever, even after the app is deleted.","example":"facebook-capi"},"name":{"type":"string","minLength":1,"maxLength":100,"description":"Display name of the app, 1-100 characters.","example":"Facebook CAPI"},"description":{"type":"string","maxLength":500,"description":"Optional summary of what the app does, at most 500 characters. Omit to leave it unset.","example":"Send events to the Facebook Conversions API."}},"required":["slug","name"]}}}},"responses":{"201":{"description":"The app was registered; the response echoes its stored representation.","content":{"application/json":{"schema":{"type":"object","properties":{"app":{"$ref":"#/components/schemas/App"}},"required":["app"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed. `invalid_app` — The app details were rejected — a malformed or reserved slug, or a name or description that is too long. `message` states which.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body","invalid_app"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"409":{"description":"`slug_taken` — The slug is already in use. Slugs are permanent and stay reserved even after an app is deleted, so choose a different one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["slug_taken"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"slug_taken"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/developer/organizations/{organizationId}/apps/{appId}":{"get":{"operationId":"getApp","tags":["Developer apps"],"summary":"Get an app","description":"Returns one of the organization’s apps by id. Use it to refresh a single app after a change instead of re-listing them all.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` scope, for a user who belongs to the addressed organization","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the app, as returned by the create and list operations.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"required":true,"description":"Unique id (UUID) of the app, as returned by the create and list operations.","name":"appId","in":"path"}],"responses":{"200":{"description":"The addressed app.","content":{"application/json":{"schema":{"type":"object","properties":{"app":{"$ref":"#/components/schemas/App"}},"required":["app"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"patch":{"operationId":"updateApp","tags":["Developer apps"],"summary":"Update an app","description":"Updates an app’s name and description. The slug is fixed at creation and cannot be changed.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` scope, for an owner or developer of the addressed organization","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the app, as returned by the create and list operations.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"required":true,"description":"Unique id (UUID) of the app, as returned by the create and list operations.","name":"appId","in":"path"}],"requestBody":{"required":true,"description":"The replacement name and optional description.","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Display name of the app, 1-100 characters.","example":"Facebook CAPI"},"description":{"type":"string","maxLength":500,"description":"Replacement summary of what the app does, at most 500 characters. Omit to clear it.","example":"Send events to the Facebook Conversions API."}},"required":["name"]}}}},"responses":{"200":{"description":"The updated app.","content":{"application/json":{"schema":{"type":"object","properties":{"app":{"$ref":"#/components/schemas/App"}},"required":["app"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed. `invalid_app` — The app details were rejected — a malformed or reserved slug, or a name or description that is too long. `message` states which.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body","invalid_app"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"delete":{"operationId":"deleteApp","tags":["Developer apps"],"summary":"Delete an app","description":"Permanently deletes an app and every version pushed to it. Refused with `in_use` while the app is still installed on any site — uninstall it everywhere first — and with `bundle_dependency` while a Live or Paused bundle includes it.\n\n#### How it works\n\nThe app’s slug stays reserved after deletion and cannot be registered again.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` scope, for an owner or developer of the addressed organization","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the app, as returned by the create and list operations.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"required":true,"description":"Unique id (UUID) of the app, as returned by the create and list operations.","name":"appId","in":"path"}],"responses":{"200":{"description":"The app was deleted; its id is no longer valid.","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true],"description":"The app was deleted; its id is no longer valid. Its slug stays reserved.","example":true}},"required":["deleted"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`in_use` — The resource is still referenced by other resources and cannot be deleted; remove the dependents first. `bundle_dependency` — A Live or Paused bundle includes this app, and nothing changed. `message` names the bundles. Change those bundles first, for example by excluding the app from them.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["in_use","bundle_dependency"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"in_use"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/developer/organizations/{organizationId}/apps/{appId}/versions":{"get":{"operationId":"listAppVersions","tags":["Developer apps"],"summary":"List app versions","description":"Lists an app’s versions newest-first, drafts included. Pass the returned `nextCursor` fields back as query parameters to page.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` scope, for a user who belongs to the addressed organization","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the app, as returned by the create and list operations.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"required":true,"description":"Unique id (UUID) of the app, as returned by the create and list operations.","name":"appId","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":200,"description":"Page size, 1-200. Defaults to 50.","example":50},"required":false,"description":"Page size, 1-200. Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","description":"The `nextCursor.createdAt` from the previous page.","example":"2026-08-17T12:00:00.000Z"},"required":false,"description":"The `nextCursor.createdAt` from the previous page.","name":"cursorCreatedAt","in":"query"},{"schema":{"type":"string","description":"The `nextCursor.id` from the previous page.","example":"7d8e9f0a-1b2c-4d3e-9f4a-5b6c7d8e9f0a"},"required":false,"description":"The `nextCursor.id` from the previous page.","name":"cursorId","in":"query"}],"responses":{"200":{"description":"A page of versions with the cursor to continue from.","content":{"application/json":{"schema":{"type":"object","properties":{"versions":{"type":"array","items":{"$ref":"#/components/schemas/AppVersion"},"description":"The app’s versions, newest first, drafts included."},"nextCursor":{"type":["object","null"],"properties":{"createdAt":{"type":"string","description":"Cursor timestamp of the last returned version.","example":"2026-08-17T12:00:00.000Z"},"id":{"type":"string","description":"Cursor id of the last returned version.","example":"7d8e9f0a-1b2c-4d3e-9f4a-5b6c7d8e9f0a"}},"required":["createdAt","id"],"description":"Pass to the next call to continue paging; null on the last page."}},"required":["versions","nextCursor"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/developer/organizations/{organizationId}/apps/{appId}/variables":{"get":{"operationId":"listAppVariables","tags":["Developer apps"],"summary":"List app variables","description":"Lists the app-scope variables the app declares, with the value stored for each. These are the developer’s own settings — one value per app, delivered identically to every site that installs it — not the per-install variables a site manager fills in.\n\n#### How it works\n\nA secret’s `value` is always null; use `set` to tell a stored secret from an unset one. The list unions every version the app has, so a name an older version declared stays visible while sites still run it.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` scope, for a user who belongs to the addressed organization","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the app, as returned by the create and list operations.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"required":true,"description":"Unique id (UUID) of the app, as returned by the create and list operations.","name":"appId","in":"path"}],"responses":{"200":{"description":"The app’s app-scope variables.","content":{"application/json":{"schema":{"type":"object","properties":{"variables":{"type":"array","items":{"$ref":"#/components/schemas/AppVariable"},"description":"Every app-scope variable any version of the app declares, in the order the earliest version that declares each one lists it. Empty when no version declares any."}},"required":["variables"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"patch":{"operationId":"setAppVariables","tags":["Developer apps"],"summary":"Set app variables","description":"Stores values for the app’s app-scope variables. The body is a partial merge: names it omits keep their current value, and a value cannot be cleared once set.\n\n#### How it works\n\nThe response is the resulting state of every variable, so no follow-up read is needed. A change reaches a running app within about five minutes; an app that needs to read a value back immediately should keep that state in its own storage instead.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` scope, for an owner or developer of the addressed organization","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the app, as returned by the create and list operations.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"required":true,"description":"Unique id (UUID) of the app, as returned by the create and list operations.","name":"appId","in":"path"}],"requestBody":{"required":true,"description":"The values to store, keyed by variable name.","content":{"application/json":{"schema":{"type":"object","properties":{"values":{"type":"object","additionalProperties":{"type":"string","minLength":1,"maxLength":490,"description":"The value to store, 1-490 bytes.","example":"https://api.example.com"},"description":"The values to store, keyed by the variable name the manifest declares. Omitted names keep their current value, and there is no way to clear one. Every name must be declared by some version of the app.","example":{"API_BASE":"https://api.example.com"}}},"required":["values"]}}}},"responses":{"200":{"description":"The app’s app-scope variables after the write.","content":{"application/json":{"schema":{"type":"object","properties":{"variables":{"type":"array","items":{"$ref":"#/components/schemas/AppVariable"},"description":"Every app-scope variable any version of the app declares, in the order the earliest version that declares each one lists it. Empty when no version declares any."}},"required":["variables"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`variable_invalid` — The app declares no variable by that name, or another party sets the name (the site manager, the app developer, or the app’s own panel); `message` names it. `variable_too_large` — A value exceeds its serialized limit: 256 KB for a `large` variable, 5 KB for another variable of a single-install app, 490 bytes for one of an app that allows multiple installs or for an app-scope variable; `message` names the variable, its size and the limit.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["variable_invalid","variable_too_large"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"variable_invalid"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/developer/organizations/{organizationId}/apps/{appId}/sites":{"get":{"operationId":"listAppSites","tags":["Developer apps"],"summary":"List app sites","description":"Lists the sites running an app, newest installation first, with the version each is on. Filter by domain with `search`, and pass the returned `nextCursor` fields back as query parameters to page.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` scope, for a user who belongs to the addressed organization","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the app, as returned by the create and list operations.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"required":true,"description":"Unique id (UUID) of the app, as returned by the create and list operations.","name":"appId","in":"path"},{"schema":{"type":"string","maxLength":200,"description":"Case-insensitive substring to match against each site’s root domain and first-party domain.","example":"shop.example"},"required":false,"description":"Case-insensitive substring to match against each site’s root domain and first-party domain.","name":"search","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"description":"Page size, 1-200. Defaults to 50.","example":50},"required":false,"description":"Page size, 1-200. Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","description":"The `nextCursor.createdAt` from the previous page.","example":"2026-08-17T12:00:00.000Z"},"required":false,"description":"The `nextCursor.createdAt` from the previous page.","name":"cursorCreatedAt","in":"query"},{"schema":{"type":"string","description":"The `nextCursor.id` from the previous page.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"},"required":false,"description":"The `nextCursor.id` from the previous page.","name":"cursorId","in":"query"}],"responses":{"200":{"description":"A page of sites with the cursor to continue from.","content":{"application/json":{"schema":{"type":"object","properties":{"sites":{"type":"array","items":{"$ref":"#/components/schemas/AppSite"},"description":"One page of sites running the app, newest installation first."},"nextCursor":{"type":["object","null"],"properties":{"createdAt":{"type":"string","description":"Installation instant of the last listed site.","example":"2026-08-17T12:00:00.000Z"},"id":{"type":"string","description":"Installation record id of the last listed site.","example":"7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"}},"required":["createdAt","id"],"description":"Pass both fields as `cursorCreatedAt` / `cursorId` for the next page; `null` on the last page."}},"required":["sites","nextCursor"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/developer/organizations/{organizationId}/apps/{appId}/sites/{domainId}":{"get":{"operationId":"getAppSite","tags":["Developer apps"],"summary":"Get an app site","description":"Reads one site running the app: its installations and, on each, the state of the variables the manifest hands to the developer. Site-managed values and secret values are never returned.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` scope, for a user who belongs to the addressed organization","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the app, as returned by the create and list operations.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"required":true,"description":"Unique id (UUID) of the app, as returned by the create and list operations.","name":"appId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the list sites operation.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the list sites operation.","name":"domainId","in":"path"}],"responses":{"200":{"description":"The site, its installations, and their developer-owned variables.","content":{"application/json":{"schema":{"type":"object","properties":{"site":{"$ref":"#/components/schemas/AppSiteDetail"}},"required":["site"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/developer/organizations/{organizationId}/apps/{appId}/sites/{domainId}/installs/{installId}/variables":{"put":{"operationId":"setAppSiteInstallVariables","tags":["Developer apps"],"summary":"Configure an app site install","description":"Stores values for the developer-owned variables of one installation on a site — a beta flag switched on for one customer, say. Only the names in the body are written; anything left out keeps its current value.\n\n#### How it works\n\nThe response is the site’s resulting state, so no follow-up read is needed. A name the manifest gives to the site manager or to the app is refused with `variable_invalid`. A change reaches the site within about five minutes and lands in the site’s activity log with you as the actor; a call that changes nothing does neither.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` scope, for an owner of the addressed organization, or a member or developer of it with support access","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the addressed apps, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the app, as returned by the create and list operations.","example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"required":true,"description":"Unique id (UUID) of the app, as returned by the create and list operations.","name":"appId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the site, as returned by the list sites operation.","example":"3f2a9c81-5d47-4e0b-8c66-91b2a7f04d15"},"required":true,"description":"Unique id (UUID) of the site, as returned by the list sites operation.","name":"domainId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the installation on that site, as returned by the get site operation.","example":"8d7c6b5a-4938-4271-a605-9e8f7a6b5c4d"},"required":true,"description":"Unique id (UUID) of the installation on that site, as returned by the get site operation.","name":"installId","in":"path"}],"requestBody":{"required":true,"description":"The values to store, keyed by variable name.","content":{"application/json":{"schema":{"type":"object","properties":{"values":{"type":"object","additionalProperties":{"anyOf":[{"type":"string","maxLength":5120,"description":"The value to store: at most 5 KB of serialized JSON for a single-install app, 490 bytes for one that allows multiple installs.","example":"v2"},{"type":"boolean","description":"The value of a `toggle` variable.","example":true},{"type":"array","items":{"type":"string"},"description":"The value of a `multiselect` variable: option values, stored in manifest order.","example":["AddToCart","Purchase"]}]},"description":"The values to store, keyed by the variable name the manifest declares with `owner: \"developer\"`. Omitted names keep their current value. A `toggle` takes a boolean; a `select` takes an option `value` or an empty string; a `multiselect` takes a list of option values or an empty list; the other types take a string.","example":{"BETA_CHECKOUT":true}}},"required":["values"]}}}},"responses":{"200":{"description":"The site after the write.","content":{"application/json":{"schema":{"type":"object","properties":{"site":{"$ref":"#/components/schemas/AppSiteDetail"}},"required":["site"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`variable_invalid` — The app declares no variable by that name, or another party sets the name (the site manager, the app developer, or the app’s own panel); `message` names it. `variable_too_large` — A value exceeds its serialized limit: 256 KB for a `large` variable, 5 KB for another variable of a single-install app, 490 bytes for one of an app that allows multiple installs or for an app-scope variable; `message` names the variable, its size and the limit. `variable_budget` — One variable’s values across every install of the app on this site exceed 5 KB together, or all `large` values of the app’s worker exceed 1 MB, removed installs included until they are purged; `message` states the size. Shorten a value before retrying; a removed install frees its share once it is purged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["variable_invalid","variable_too_large","variable_budget"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"variable_invalid"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/developer/organizations/{organizationId}/bundles":{"get":{"operationId":"listBundles","tags":["Developer bundles"],"summary":"List bundles","description":"Lists one page of the organization’s bundles, newest first. Call it to discover the `bundleId` the other bundle operations reference.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` or `bundles` scope, for an owner of the addressed organization or a member with the `bundles` finance area and all apps","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"date-time","description":"The `nextCursor.createdAt` of the previous page.","example":"2026-11-05T12:00:00.000Z"},"required":false,"description":"The `nextCursor.createdAt` of the previous page.","name":"cursorCreatedAt","in":"query"},{"schema":{"type":"string","description":"The `nextCursor.id` of the previous page.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"required":false,"description":"The `nextCursor.id` of the previous page.","name":"cursorId","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"description":"Page size, 1–200 (default 50).","example":50},"required":false,"description":"Page size, 1–200 (default 50).","name":"limit","in":"query"}],"responses":{"200":{"description":"The organization’s bundles.","content":{"application/json":{"schema":{"type":"object","properties":{"bundles":{"type":"array","items":{"$ref":"#/components/schemas/Bundle"},"description":"One page of the organization’s bundles, newest first."},"nextCursor":{"type":["object","null"],"properties":{"createdAt":{"type":"string","description":"Creation instant of the last listed bundle.","example":"2026-11-05T12:00:00.000Z"},"id":{"type":"string","description":"Id of the last listed bundle.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"}},"required":["createdAt","id"],"description":"Pass both fields as `cursorCreatedAt` / `cursorId` for the next page; `null` on the last page."}},"required":["bundles","nextCursor"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known. `bundles_scope_required` — The bearer credential has neither the `developer` nor the `bundles` scope, so it reaches no bundle operation whatever the role of its user. Authorize again to get a token with one of them.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden","bundles_scope_required"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"post":{"operationId":"createBundle","tags":["Developer bundles"],"summary":"Create a bundle","description":"Creates a Draft bundle under the organization. A Draft needs only a name; the returned `bundleId` is what the other bundle operations reference.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` or `bundles` scope, for an owner of the addressed organization or a member with the `bundles` finance area and all apps","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"}],"requestBody":{"required":true,"description":"The new bundle’s name, and its optional descriptions, audience, apps and pricing.","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Display name of the bundle, 1-100 characters.","example":"Growth Stack"},"description":{"type":"string","maxLength":200,"description":"One line about what a team gets, at most 200 characters and with no line break. Omit for none.","example":"Everything a store needs to measure its marketing."},"longDescription":{"type":"string","maxLength":5000,"description":"Longer description, at most 5000 characters. Its line breaks are kept. Omit for none.","example":"Who the bundle is for.\n\nHow support works."},"audience":{"type":"string","enum":["public","private"],"description":"Who can reach the bundle. A new bundle without it is `private`, and an update without it keeps the current audience. Only a Draft can change it.","example":"public"},"appMode":{"type":"string","enum":["selected","all","exclude"],"description":"How the bundle picks its apps. A new bundle without it is `selected`, and an update without it keeps the current mode. `all` stores no list.","example":"exclude"},"appIds":{"type":"array","items":{"type":"string","format":"uuid","description":"Unique id (UUID) of a published app of this organization.","example":"7f3a1c92-4b6d-4e8a-b1d3-5c9e2f7a6b10"},"description":"The app list for `selected` or `exclude`, as listed by the bundle apps operation. Omit to keep the current list. An id that is not a published app of this organization is refused, and so is a list with `all`."},"pricingModel":{"type":"string","enum":["fixed","fixed_usage","usage","free"],"description":"How the bundle charges. A new bundle without it is `fixed`, and an update without it keeps the current model. Publish refuses a field the model doesn’t use; a Draft can hold one.","example":"fixed"},"basePriceCents":{"type":["integer","null"],"minimum":0,"maximum":100000000,"description":"Base price per team, in US cents, at most 100000000. `fixed` and `fixed_usage` need one above 0 to publish. Omit to keep the current value, or send null to clear it.","example":7200000},"billingInterval":{"type":["string","null"],"enum":["monthly","yearly","one_time",null],"description":"How often the base price is billed. `fixed` and `fixed_usage` need one to publish. Omit to keep the current value, or send null to clear it.","example":"yearly"},"trialDays":{"type":["integer","null"],"minimum":0,"maximum":30,"description":"Length of the free trial, 0 to 30 days. `free` has none. Omit to keep the current value, or send null to clear it.","example":14},"siteLimit":{"anyOf":[{"type":"integer","minimum":1,"maximum":10000,"description":"The number of sites, 1 to 10000.","example":3},{"type":"string","enum":["unlimited"],"description":"No site limit.","example":"unlimited"}],"description":"How many sites a team can use the bundle on. A new bundle without it has 1, and an update without it keeps the current limit.","example":3},"extraSitePriceCents":{"type":["integer","null"],"minimum":0,"maximum":100000000,"description":"Price of each site past the limit, in US cents. Only a base price model with a fixed limit can sell extra sites, and then the price must be above 0 to publish. Omit to keep the current value, or send null to stop selling them.","example":50000},"services":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"description":"Name of the service, at most 100 characters. Needed to publish.","example":"Priority support"},"detail":{"type":"string","maxLength":200,"default":"","description":"What the team gets, at most 200 characters.","example":"4-hour response"},"priceCents":{"type":["integer","null"],"minimum":0,"maximum":100000000,"description":"What the service costs on its own, in US cents. A price above 0 is needed to publish.","example":20000},"basis":{"type":"string","enum":["monthly","one_time"],"description":"How the price on its own is billed.","example":"monthly"}},"required":["name","priceCents","basis"],"description":"One service the developer delivers."},"maxItems":20,"description":"The services the bundle price covers, at most 20. Omit to keep the current list."},"usageCapCents":{"type":["integer","null"],"minimum":0,"maximum":100000000,"description":"The most usage can add to a team’s bill each month, in US cents, at most 100000000. `fixed_usage` and `usage` need one above 0 to publish, and the other models refuse one. Omit to keep the current value, or send null to clear it.","example":50000},"meterTerms":{"type":"array","items":{"type":"object","properties":{"appId":{"type":"string","format":"uuid","description":"Unique id (UUID) of the app that reports the meter.","example":"7f3a1c92-4b6d-4e8a-b1d3-5c9e2f7a6b10"},"key":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,39}$","description":"Key of the meter in that app.","example":"events"},"name":{"type":"string","maxLength":60,"default":"","description":"Name of the meter on the bundle, at most 60 characters. Blank uses the key.","example":"Events"},"unit":{"type":"string","maxLength":60,"default":"","description":"Plural unit, at most 60 characters. Needed to publish.","example":"events"},"includedAmount":{"type":"integer","minimum":0,"maximum":1000000000000,"default":0,"description":"Units included each month for the whole team, across its sites.","example":100000},"priceMicros":{"type":["integer","null"],"minimum":0,"maximum":1000000000,"description":"Price past the included amount, in US micro-dollars. Null or 0 leaves the meter free, and stores no term.","example":500000},"perUnits":{"type":["integer","null"],"minimum":1,"maximum":1000000,"description":"How many units that price covers. Needed to publish.","example":1000}},"required":["appId","key","priceMicros","perUnits"],"description":"What one meter of one app costs on the bundle."},"maxItems":100,"description":"The meter terms of a usage model, priced or not, at most 100. Omit to keep the current list. Publish refuses a term no app in the bundle reports, and any term on `fixed` or `free`; a Draft can hold one."}},"required":["name"]}}}},"responses":{"201":{"description":"The Draft was created; the response echoes its stored representation.","content":{"application/json":{"schema":{"type":"object","properties":{"bundle":{"$ref":"#/components/schemas/Bundle"}},"required":["bundle"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed. `invalid_bundle` — The bundle details were rejected, such as a name or description that is empty or too long, a description with a line break, an app that is not a published app of the organization, or a price, trial, site limit, service, link label or link limit out of range. `message` states which.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body","invalid_bundle"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known. `bundles_scope_required` — The bearer credential has neither the `developer` nor the `bundles` scope, so it reaches no bundle operation whatever the role of its user. Authorize again to get a token with one of them.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden","bundles_scope_required"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/developer/organizations/{organizationId}/bundles/{bundleId}":{"get":{"operationId":"getBundle","tags":["Developer bundles"],"summary":"Get a bundle","description":"Returns one bundle of the organization. A bundle of another organization answers `not_found`.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` or `bundles` scope, for an owner of the addressed organization or a member with the `bundles` finance area and all apps","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"required":true,"description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","name":"bundleId","in":"path"}],"responses":{"200":{"description":"The bundle.","content":{"application/json":{"schema":{"type":"object","properties":{"bundle":{"$ref":"#/components/schemas/Bundle"}},"required":["bundle"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known. `bundles_scope_required` — The bearer credential has neither the `developer` nor the `bundles` scope, so it reaches no bundle operation whatever the role of its user. Authorize again to get a token with one of them.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden","bundles_scope_required"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"patch":{"operationId":"updateBundle","tags":["Developer bundles"],"summary":"Update a bundle","description":"Replaces a bundle’s name, descriptions, apps and pricing, and its audience while it is a Draft. A field the body omits stays, and `null` clears a description or a pricing field that allows it. An update to a Live or Paused bundle applies at once, so it must pass the publish checks.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` or `bundles` scope, for an owner of the addressed organization or a member with the `bundles` finance area and all apps","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"required":true,"description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","name":"bundleId","in":"path"}],"requestBody":{"required":true,"description":"The replacement name, and the optional descriptions, audience, apps and pricing.","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Display name of the bundle, 1-100 characters.","example":"Growth Stack"},"description":{"type":["string","null"],"maxLength":200,"description":"One line about what a team gets, at most 200 characters and with no line break. Omit to keep it, or send null to clear it. A blank string also clears it.","example":"Everything a store needs to measure its marketing."},"longDescription":{"type":["string","null"],"maxLength":5000,"description":"Longer description, at most 5000 characters. Its line breaks are kept. Omit to keep it, or send null to clear it. A blank string also clears it.","example":"Who the bundle is for.\n\nHow support works."},"audience":{"type":"string","enum":["public","private"],"description":"Who can reach the bundle. A new bundle without it is `private`, and an update without it keeps the current audience. Only a Draft can change it.","example":"public"},"appMode":{"type":"string","enum":["selected","all","exclude"],"description":"How the bundle picks its apps. A new bundle without it is `selected`, and an update without it keeps the current mode. `all` stores no list.","example":"exclude"},"appIds":{"type":"array","items":{"type":"string","format":"uuid","description":"Unique id (UUID) of a published app of this organization.","example":"7f3a1c92-4b6d-4e8a-b1d3-5c9e2f7a6b10"},"description":"The app list for `selected` or `exclude`, as listed by the bundle apps operation. Omit to keep the current list. An id that is not a published app of this organization is refused, and so is a list with `all`."},"pricingModel":{"type":"string","enum":["fixed","fixed_usage","usage","free"],"description":"How the bundle charges. A new bundle without it is `fixed`, and an update without it keeps the current model. Publish refuses a field the model doesn’t use; a Draft can hold one.","example":"fixed"},"basePriceCents":{"type":["integer","null"],"minimum":0,"maximum":100000000,"description":"Base price per team, in US cents, at most 100000000. `fixed` and `fixed_usage` need one above 0 to publish. Omit to keep the current value, or send null to clear it.","example":7200000},"billingInterval":{"type":["string","null"],"enum":["monthly","yearly","one_time",null],"description":"How often the base price is billed. `fixed` and `fixed_usage` need one to publish. Omit to keep the current value, or send null to clear it.","example":"yearly"},"trialDays":{"type":["integer","null"],"minimum":0,"maximum":30,"description":"Length of the free trial, 0 to 30 days. `free` has none. Omit to keep the current value, or send null to clear it.","example":14},"siteLimit":{"anyOf":[{"type":"integer","minimum":1,"maximum":10000,"description":"The number of sites, 1 to 10000.","example":3},{"type":"string","enum":["unlimited"],"description":"No site limit.","example":"unlimited"}],"description":"How many sites a team can use the bundle on. A new bundle without it has 1, and an update without it keeps the current limit.","example":3},"extraSitePriceCents":{"type":["integer","null"],"minimum":0,"maximum":100000000,"description":"Price of each site past the limit, in US cents. Only a base price model with a fixed limit can sell extra sites, and then the price must be above 0 to publish. Omit to keep the current value, or send null to stop selling them.","example":50000},"services":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"description":"Name of the service, at most 100 characters. Needed to publish.","example":"Priority support"},"detail":{"type":"string","maxLength":200,"default":"","description":"What the team gets, at most 200 characters.","example":"4-hour response"},"priceCents":{"type":["integer","null"],"minimum":0,"maximum":100000000,"description":"What the service costs on its own, in US cents. A price above 0 is needed to publish.","example":20000},"basis":{"type":"string","enum":["monthly","one_time"],"description":"How the price on its own is billed.","example":"monthly"}},"required":["name","priceCents","basis"],"description":"One service the developer delivers."},"maxItems":20,"description":"The services the bundle price covers, at most 20. Omit to keep the current list."},"usageCapCents":{"type":["integer","null"],"minimum":0,"maximum":100000000,"description":"The most usage can add to a team’s bill each month, in US cents, at most 100000000. `fixed_usage` and `usage` need one above 0 to publish, and the other models refuse one. Omit to keep the current value, or send null to clear it.","example":50000},"meterTerms":{"type":"array","items":{"type":"object","properties":{"appId":{"type":"string","format":"uuid","description":"Unique id (UUID) of the app that reports the meter.","example":"7f3a1c92-4b6d-4e8a-b1d3-5c9e2f7a6b10"},"key":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,39}$","description":"Key of the meter in that app.","example":"events"},"name":{"type":"string","maxLength":60,"default":"","description":"Name of the meter on the bundle, at most 60 characters. Blank uses the key.","example":"Events"},"unit":{"type":"string","maxLength":60,"default":"","description":"Plural unit, at most 60 characters. Needed to publish.","example":"events"},"includedAmount":{"type":"integer","minimum":0,"maximum":1000000000000,"default":0,"description":"Units included each month for the whole team, across its sites.","example":100000},"priceMicros":{"type":["integer","null"],"minimum":0,"maximum":1000000000,"description":"Price past the included amount, in US micro-dollars. Null or 0 leaves the meter free, and stores no term.","example":500000},"perUnits":{"type":["integer","null"],"minimum":1,"maximum":1000000,"description":"How many units that price covers. Needed to publish.","example":1000}},"required":["appId","key","priceMicros","perUnits"],"description":"What one meter of one app costs on the bundle."},"maxItems":100,"description":"The meter terms of a usage model, priced or not, at most 100. Omit to keep the current list. Publish refuses a term no app in the bundle reports, and any term on `fixed` or `free`; a Draft can hold one."}},"required":["name"]}}}},"responses":{"200":{"description":"The updated bundle.","content":{"application/json":{"schema":{"type":"object","properties":{"bundle":{"$ref":"#/components/schemas/Bundle"},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/BundlePublishIssue"},"description":"What the publish checks found that doesn’t block. Empty when they did not run."}},"required":["bundle","warnings"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed. `invalid_bundle` — The bundle details were rejected, such as a name or description that is empty or too long, a description with a line break, an app that is not a published app of the organization, or a price, trial, site limit, service, link label or link limit out of range. `message` states which.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body","invalid_bundle"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known. `bundles_scope_required` — The bearer credential has neither the `developer` nor the `bundles` scope, so it reaches no bundle operation whatever the role of its user. Authorize again to get a token with one of them.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden","bundles_scope_required"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`bundle_audience_locked` — The body changes the audience of a bundle that has left Draft. Nothing changed. Duplicate the bundle to offer it to another audience.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["bundle_audience_locked"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"bundle_audience_locked"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"422":{"description":"`bundle_not_publishable` — The bundle fails the publish checks, and nothing changed. `problems` lists everything to fix, and `warnings` lists what wouldn’t block.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["bundle_not_publishable"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"bundle_not_publishable"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"problems":{"type":"array","items":{"$ref":"#/components/schemas/BundlePublishIssue"},"description":"Every problem that refuses the bundle; fix them all, then try again."},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/BundlePublishIssue"},"description":"Everything the checks found that doesn’t block."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"delete":{"operationId":"deleteBundle","tags":["Developer bundles"],"summary":"Delete a bundle","description":"Permanently deletes a Draft bundle. A bundle that has left Draft stays.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` or `bundles` scope, for an owner of the addressed organization or a member with the `bundles` finance area and all apps","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"required":true,"description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","name":"bundleId","in":"path"}],"responses":{"200":{"description":"The bundle was deleted; its id is no longer valid.","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true],"description":"The bundle was deleted; its id is no longer valid.","example":true}},"required":["deleted"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known. `bundles_scope_required` — The bearer credential has neither the `developer` nor the `bundles` scope, so it reaches no bundle operation whatever the role of its user. Authorize again to get a token with one of them.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden","bundles_scope_required"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`bundle_not_draft` — The bundle has left Draft, and only a Draft bundle can be deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["bundle_not_draft"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"bundle_not_draft"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/developer/organizations/{organizationId}/bundles/{bundleId}/publish":{"post":{"operationId":"publishBundle","tags":["Developer bundles"],"summary":"Publish a bundle","description":"Moves a Draft or Retired bundle to Live. The first publish locks the audience. To change a Live bundle, update it.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` or `bundles` scope, for an owner of the addressed organization or a member with the `bundles` finance area and all apps","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"required":true,"description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","name":"bundleId","in":"path"}],"responses":{"200":{"description":"The bundle is Live; `warnings` lists what the publish checks found that doesn’t block.","content":{"application/json":{"schema":{"type":"object","properties":{"bundle":{"$ref":"#/components/schemas/Bundle"},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/BundlePublishIssue"},"description":"What the publish checks found that doesn’t block. Empty when they did not run."}},"required":["bundle","warnings"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known. `bundles_scope_required` — The bearer credential has neither the `developer` nor the `bundles` scope, so it reaches no bundle operation whatever the role of its user. Authorize again to get a token with one of them.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden","bundles_scope_required"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`bundle_status_conflict` — The bundle’s status doesn’t allow this action. A Draft or Retired bundle can be published, a Live bundle can be retired, and a Paused bundle can only be edited. `message` states which.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["bundle_status_conflict"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"bundle_status_conflict"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"422":{"description":"`bundle_not_publishable` — The bundle fails the publish checks, and nothing changed. `problems` lists everything to fix, and `warnings` lists what wouldn’t block.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["bundle_not_publishable"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"bundle_not_publishable"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"problems":{"type":"array","items":{"$ref":"#/components/schemas/BundlePublishIssue"},"description":"Every problem that refuses the bundle; fix them all, then try again."},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/BundlePublishIssue"},"description":"Everything the checks found that doesn’t block."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/developer/organizations/{organizationId}/bundles/{bundleId}/retire":{"post":{"operationId":"retireBundle","tags":["Developer bundles"],"summary":"Retire a bundle","description":"Stops selling a Live bundle, while its current buyers keep it. Publish it again to return it to Live.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` or `bundles` scope, for an owner of the addressed organization or a member with the `bundles` finance area and all apps","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"required":true,"description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","name":"bundleId","in":"path"}],"responses":{"200":{"description":"The bundle is Retired.","content":{"application/json":{"schema":{"type":"object","properties":{"bundle":{"$ref":"#/components/schemas/Bundle"}},"required":["bundle"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known. `bundles_scope_required` — The bearer credential has neither the `developer` nor the `bundles` scope, so it reaches no bundle operation whatever the role of its user. Authorize again to get a token with one of them.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden","bundles_scope_required"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`bundle_status_conflict` — The bundle’s status doesn’t allow this action. A Draft or Retired bundle can be published, a Live bundle can be retired, and a Paused bundle can only be edited. `message` states which.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["bundle_status_conflict"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"bundle_status_conflict"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/developer/organizations/{organizationId}/bundles/{bundleId}/duplicate":{"post":{"operationId":"duplicateBundle","tags":["Developer bundles"],"summary":"Duplicate a bundle","description":"Copies a bundle that isn’t Paused into a new Draft, with its audience and without its links. Use it to make a similar offer, or to offer a bundle to another audience.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` or `bundles` scope, for an owner of the addressed organization or a member with the `bundles` finance area and all apps","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"required":true,"description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","name":"bundleId","in":"path"}],"responses":{"201":{"description":"The new Draft.","content":{"application/json":{"schema":{"type":"object","properties":{"bundle":{"$ref":"#/components/schemas/Bundle"}},"required":["bundle"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known. `bundles_scope_required` — The bearer credential has neither the `developer` nor the `bundles` scope, so it reaches no bundle operation whatever the role of its user. Authorize again to get a token with one of them.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden","bundles_scope_required"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`bundle_status_conflict` — The bundle’s status doesn’t allow this action. A Draft or Retired bundle can be published, a Live bundle can be retired, and a Paused bundle can only be edited. `message` states which.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["bundle_status_conflict"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"bundle_status_conflict"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/developer/organizations/{organizationId}/bundle-apps":{"get":{"operationId":"listBundleApps","tags":["Developer bundles"],"summary":"List apps for a bundle","description":"Lists one page of the organization’s published apps, A–Z by name, with each app’s store presence, own price and meter keys. Call it to find the `appIds` a bundle can use.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` or `bundles` scope, for an owner of the addressed organization or a member with the `bundles` finance area and all apps","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","description":"Finds apps by part of the name, in any case.","example":"capi"},"required":false,"description":"Finds apps by part of the name, in any case.","name":"search","in":"query"},{"schema":{"type":"string","description":"The `nextCursor.name` of the previous page.","example":"Facebook CAPI"},"required":false,"description":"The `nextCursor.name` of the previous page.","name":"cursorName","in":"query"},{"schema":{"type":"string","description":"The `nextCursor.id` of the previous page.","example":"7f3a1c92-4b6d-4e8a-b1d3-5c9e2f7a6b10"},"required":false,"description":"The `nextCursor.id` of the previous page.","name":"cursorId","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"description":"Page size, 1–200 (default 50).","example":50},"required":false,"description":"Page size, 1–200 (default 50).","name":"limit","in":"query"}],"responses":{"200":{"description":"The organization’s published apps.","content":{"application/json":{"schema":{"type":"object","properties":{"apps":{"type":"array","items":{"$ref":"#/components/schemas/BundleApp"},"description":"One page of the organization’s published apps, A–Z by name."},"nextCursor":{"type":["object","null"],"properties":{"name":{"type":"string","description":"Name of the last listed app.","example":"Facebook CAPI"},"id":{"type":"string","description":"Id of the last listed app.","example":"7f3a1c92-4b6d-4e8a-b1d3-5c9e2f7a6b10"}},"required":["name","id"],"description":"Pass both fields as `cursorName` / `cursorId` for the next page; `null` on the last page."}},"required":["apps","nextCursor"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known. `bundles_scope_required` — The bearer credential has neither the `developer` nor the `bundles` scope, so it reaches no bundle operation whatever the role of its user. Authorize again to get a token with one of them.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden","bundles_scope_required"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/developer/organizations/{organizationId}/bundles/{bundleId}/links":{"get":{"operationId":"listBundleLinks","tags":["Developer bundles"],"summary":"List bundle links","description":"Lists one page of a bundle’s links, newest first, revoked ones included. A Draft or a public bundle has none.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` or `bundles` scope, for an owner of the addressed organization or a member with the `bundles` finance area and all apps","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"required":true,"description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","name":"bundleId","in":"path"},{"schema":{"type":"string","format":"date-time","description":"The `nextCursor.createdAt` of the previous page.","example":"2026-11-05T12:00:00.000Z"},"required":false,"description":"The `nextCursor.createdAt` of the previous page.","name":"cursorCreatedAt","in":"query"},{"schema":{"type":"string","description":"The `nextCursor.id` of the previous page.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"required":false,"description":"The `nextCursor.id` of the previous page.","name":"cursorId","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"description":"Page size, 1–200 (default 50).","example":50},"required":false,"description":"Page size, 1–200 (default 50).","name":"limit","in":"query"}],"responses":{"200":{"description":"The bundle’s links.","content":{"application/json":{"schema":{"type":"object","properties":{"links":{"type":"array","items":{"$ref":"#/components/schemas/BundleLink"},"description":"One page of the bundle’s links, newest first, revoked ones included."},"nextCursor":{"type":["object","null"],"properties":{"createdAt":{"type":"string","description":"Creation instant of the last listed link.","example":"2026-11-05T12:00:00.000Z"},"id":{"type":"string","description":"Id of the last listed link.","example":"5d2c8e71-3f4a-4b90-8c16-e7a9d0b2f345"}},"required":["createdAt","id"],"description":"Pass both fields as `cursorCreatedAt` / `cursorId` for the next page; `null` on the last page."}},"required":["links","nextCursor"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known. `bundles_scope_required` — The bearer credential has neither the `developer` nor the `bundles` scope, so it reaches no bundle operation whatever the role of its user. Authorize again to get a token with one of them.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden","bundles_scope_required"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}},"post":{"operationId":"createBundleLink","tags":["Developer bundles"],"summary":"Create a bundle link","description":"Creates a link on a Live or Retired private bundle. Send the returned `url` to a team. Its use count starts at 0, and each link has its own token.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` or `bundles` scope, for an owner of the addressed organization or a member with the `bundles` finance area and all apps","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"required":true,"description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","name":"bundleId","in":"path"}],"requestBody":{"required":true,"description":"The label and limit of the link.","content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":100,"description":"What to call the link, 1-100 characters.","example":"Acme partner offer"},"limit":{"anyOf":[{"type":"integer","minimum":1,"maximum":1000000,"description":"A whole number from 1 to 1000000.","example":25},{"type":"string","enum":["unlimited"],"description":"No limit.","example":"unlimited"}],"description":"How many teams can buy through the link.","example":25}},"required":["label","limit"]}}}},"responses":{"201":{"description":"The created link.","content":{"application/json":{"schema":{"type":"object","properties":{"link":{"$ref":"#/components/schemas/BundleLink"}},"required":["link"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed. `invalid_bundle` — The bundle details were rejected, such as a name or description that is empty or too long, a description with a line break, an app that is not a published app of the organization, or a price, trial, site limit, service, link label or link limit out of range. `message` states which.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body","invalid_bundle"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known. `bundles_scope_required` — The bearer credential has neither the `developer` nor the `bundles` scope, so it reaches no bundle operation whatever the role of its user. Authorize again to get a token with one of them.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden","bundles_scope_required"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`bundle_links_unavailable` — A new link needs a Live or Retired private bundle, so this bundle takes none. Nothing changed. Publish a Draft first; a Paused bundle takes one once Blotout lifts the pause; a public bundle can’t have links.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["bundle_links_unavailable"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"bundle_links_unavailable"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/developer/organizations/{organizationId}/bundles/{bundleId}/links/{linkId}":{"patch":{"operationId":"updateBundleLink","tags":["Developer bundles"],"summary":"Update a bundle link","description":"Replaces a link’s label and limit, and keeps its URL. A limit below the current use count is accepted and only stops further purchases.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` or `bundles` scope, for an owner of the addressed organization or a member with the `bundles` finance area and all apps","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"required":true,"description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","name":"bundleId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the link, as returned by the create and list operations.","example":"5d2c8e71-3f4a-4b90-8c16-e7a9d0b2f345"},"required":true,"description":"Unique id (UUID) of the link, as returned by the create and list operations.","name":"linkId","in":"path"}],"requestBody":{"required":true,"description":"The replacement label and limit.","content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":100,"description":"What to call the link, 1-100 characters.","example":"Acme partner offer"},"limit":{"anyOf":[{"type":"integer","minimum":1,"maximum":1000000,"description":"A whole number from 1 to 1000000.","example":25},{"type":"string","enum":["unlimited"],"description":"No limit.","example":"unlimited"}],"description":"How many teams can buy through the link.","example":25}},"required":["label","limit"]}}}},"responses":{"200":{"description":"The updated link.","content":{"application/json":{"schema":{"type":"object","properties":{"link":{"$ref":"#/components/schemas/BundleLink"}},"required":["link"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter. `invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed. `invalid_bundle` — The bundle details were rejected, such as a name or description that is empty or too long, a description with a line break, an app that is not a published app of the organization, or a price, trial, site limit, service, link label or link limit out of range. `message` states which.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params","invalid_body","invalid_bundle"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known. `bundles_scope_required` — The bearer credential has neither the `developer` nor the `bundles` scope, so it reaches no bundle operation whatever the role of its user. Authorize again to get a token with one of them.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden","bundles_scope_required"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"409":{"description":"`bundle_link_revoked` — The link is revoked, which is permanent: the developer can’t change it and a team can’t buy through it. Nothing changed. The developer creates a new link instead.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["bundle_link_revoked"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"bundle_link_revoked"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/developer/organizations/{organizationId}/bundles/{bundleId}/links/{linkId}/revoke":{"post":{"operationId":"revokeBundleLink","tags":["Developer bundles"],"summary":"Revoke a bundle link","description":"Revokes a link permanently, whatever the bundle’s status, so a leaked link stops working. It can’t be restored. Safe to retry: revoking a revoked link changes nothing.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token with the `developer` or `bundles` scope, for an owner of the addressed organization or a member with the `bundles` finance area and all apps","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","example":"9c1d2b34-5e67-4f89-a0b1-2c3d4e5f6a7b"},"required":true,"description":"Unique id (UUID) of the organization that owns the bundles, as listed by `GET /me` under `organizations`.","name":"organizationId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"required":true,"description":"Unique id (UUID) of the bundle, as returned by the create and list operations.","name":"bundleId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the link, as returned by the create and list operations.","example":"5d2c8e71-3f4a-4b90-8c16-e7a9d0b2f345"},"required":true,"description":"Unique id (UUID) of the link, as returned by the create and list operations.","name":"linkId","in":"path"}],"responses":{"200":{"description":"The revoked link.","content":{"application/json":{"schema":{"type":"object","properties":{"link":{"$ref":"#/components/schemas/BundleLink"}},"required":["link"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known. `bundles_scope_required` — The bearer credential has neither the `developer` nor the `bundles` scope, so it reaches no bundle operation whatever the role of its user. Authorize again to get a token with one of them.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden","bundles_scope_required"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/app-store/apps":{"get":{"operationId":"searchStoreApps","tags":["App store"],"summary":"Search the app store","description":"Searches the apps in the app store, A–Z by name. Call it to find an app by words or by category; the `slug` of a result is the `appSlug` the other app store operation takes.\n\n#### How it works\n\nSearch matches whole words, with common endings ignored: `purchases` finds `purchase`, but `klav` does not find `Klaviyo`. Page with `cursor` from the previous response’s `nextCursor`; a null cursor means the last page.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token whose user belongs to a team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","description":"Words to search for. An app matches when its name holds every word, or its tagline and description together do. Omit it to list every app.","example":"conversion tracking"},"required":false,"description":"Words to search for. An app matches when its name holds every word, or its tagline and description together do. Omit it to list every app.","name":"q","in":"query"},{"schema":{"type":"string","enum":["advertising","analytics","consent_privacy","customer_data","email_sms","personalization","security","developer_tools"],"description":"Return only apps listed in this category.","example":"advertising"},"required":false,"description":"Return only apps listed in this category.","name":"category","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many apps to return, 1–200. The default is 50.","example":50},"required":false,"description":"How many apps to return, 1–200. The default is 50.","name":"limit","in":"query"},{"schema":{"type":"string","description":"Continue after this app slug, from a previous response’s `nextCursor`.","example":"facebook-capi"},"required":false,"description":"Continue after this app slug, from a previous response’s `nextCursor`.","name":"cursor","in":"query"}],"responses":{"200":{"description":"The page of apps.","content":{"application/json":{"schema":{"type":"object","properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/StoreAppCard"},"description":"The page of apps, A–Z by name."},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page, or null on the last one.","example":"facebook-capi"}},"required":["records","nextCursor"]}}}},"400":{"description":"`invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_body"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/app-store/apps/{appSlug}":{"get":{"operationId":"getStoreApp","tags":["App store"],"summary":"Get an app store app","description":"Returns one app store app with its full listing: the description, the features, the screenshots, the publisher’s links, and what its newest approved version may do on a site. Call it before you install an app.\n\n#### How it works\n\n`facts` describes the newest approved version, and `versions` lists every approved one. `not_found` means no app has this slug, or the app is not in the app store.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token whose user belongs to a team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,29}$","description":"Slug of the app, as the search operation returns it.","example":"facebook-capi"},"required":true,"description":"Slug of the app, as the search operation returns it.","name":"appSlug","in":"path"}],"responses":{"200":{"description":"The app and its listing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoreApp"}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/app-store/bundles":{"get":{"operationId":"listStoreBundles","tags":["App store"],"summary":"List app store bundles","description":"Lists the bundles a team can buy from the app store, newest first: each one’s price, trial, site limit, services, usage terms, the apps it holds right now and how its price compares with buying them separately. Call it to show a team what is on offer.\n\n#### How it works\n\nOnly Live public bundles that can be sold right now are listed, so a page can hold fewer bundles than `limit`. Page with `cursorCreatedAt` and `cursorId` from the previous response’s `nextCursor`; a null cursor means the last page.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token whose user belongs to a team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"date-time","description":"The `nextCursor.createdAt` of the previous page.","example":"2026-11-05T12:00:00.000Z"},"required":false,"description":"The `nextCursor.createdAt` of the previous page.","name":"cursorCreatedAt","in":"query"},{"schema":{"type":"string","description":"The `nextCursor.id` of the previous page.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"required":false,"description":"The `nextCursor.id` of the previous page.","name":"cursorId","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"description":"Page size, 1–200 (default 50).","example":50},"required":false,"description":"Page size, 1–200 (default 50).","name":"limit","in":"query"}],"responses":{"200":{"description":"The page of bundles.","content":{"application/json":{"schema":{"type":"object","properties":{"bundles":{"type":"array","items":{"$ref":"#/components/schemas/StoreBundle"},"description":"One page of the bundles on offer, newest first."},"nextCursor":{"type":["object","null"],"properties":{"createdAt":{"type":"string","description":"Creation instant of the last listed bundle.","example":"2026-11-05T12:00:00.000Z"},"id":{"type":"string","description":"Id of the last listed bundle.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"}},"required":["createdAt","id"],"description":"Pass both fields as `cursorCreatedAt` / `cursorId` for the next page; `null` on the last page."}},"required":["bundles","nextCursor"]}}}},"400":{"description":"`invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_body"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/app-store/bundles/{bundleId}":{"get":{"operationId":"getStoreBundle","tags":["App store"],"summary":"Get an app store bundle","description":"Returns one bundle a team can buy from the app store, with its price, trial, site limit, services, usage terms, the apps it holds right now and how its price compares with buying them separately.\n\n#### How it works\n\n`not_found` means no Live public bundle has this id, or the bundle cannot be sold right now.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token whose user belongs to a team","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Unique id (UUID) of the bundle, as the list operation returns it.","example":"2b7e4d10-8a3c-4f56-9e21-7c0d5b8f3a64"},"required":true,"description":"Unique id (UUID) of the bundle, as the list operation returns it.","name":"bundleId","in":"path"}],"responses":{"200":{"description":"The bundle.","content":{"application/json":{"schema":{"type":"object","properties":{"bundle":{"$ref":"#/components/schemas/StoreBundle"}},"required":["bundle"]}}}},"400":{"description":"`invalid_params` — A path parameter failed validation (for example a malformed UUID); `details` pinpoints the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_params"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_params"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}},"/app-store/bundle-link":{"get":{"operationId":"getStoreBundleLink","tags":["App store"],"summary":"Read a bundle link","description":"Returns what a bundle link offers: the private bundle behind it, shaped as the bundle operations return it, or why the offer has ended. Call it with the `token` from a link a developer shared, before a team buys through it.\n\n#### How it works\n\nReading a link uses none of its purchases. `not_found` means no link has this token.\n\n#### Required permissions\n\n- None beyond a valid token; requires an OAuth token for a signed-in user","security":[{"QintoAccessToken":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":200,"description":"The token of the bundle link, from its URL.","example":"bl_7f3a1c92"},"required":true,"description":"The token of the bundle link, from its URL.","name":"token","in":"query"}],"responses":{"200":{"description":"What the link offers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoreBundleLink"}}}},"400":{"description":"`invalid_body` — The JSON body is unparseable or failed schema validation; `details` pinpoints the offending fields when the body could be parsed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_body"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"invalid_body"},"details":{"type":"object","additionalProperties":{},"description":"Field-level validation errors: a tree keyed by input property, each node carrying an `errors` array of human-readable messages. Render it to help the caller correct the request.","example":{"errors":[],"properties":{"teamId":{"errors":["Invalid UUID"]}}}}},"required":["error"]}}}},"401":{"description":"`unauthenticated` — The `Authorization: Bearer` token is missing, malformed, or no longer valid. Generate a team API token or obtain a new OAuth access token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"unauthenticated"}},"required":["error"]}}}},"403":{"description":"`forbidden` — The bearer credential lacks the required permission or belongs to another team, or its user lacks the organization role a developer operation needs. Update its policies, use a credential bound to the addressed team, or ask an organization owner for the role; `message` states the reason when one is known.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"forbidden"},"message":{"type":"string","description":"Human-readable reason for this specific failure, intended for display — do not parse it programmatically.","example":"The Cloudflare API token is invalid or expired."}},"required":["error"]}}}},"404":{"description":"`not_found` — The addressed resource does not exist within this team; check the id and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"not_found"}},"required":["error"]}}}},"500":{"description":"`internal` — Unexpected server error. Nothing is guaranteed to have been persisted; idempotent operations are safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["internal"],"description":"Machine-readable error slug; switch on this value rather than on the HTTP status alone.","example":"internal"}},"required":["error"]}}}}}}}},"webhooks":{}}