Dropto · Schema

SiteDetail

Response of `GET /sites/{siteId}`.

HostingArtificial IntelligenceStatic SitesDeveloper ToolsCloud

Properties

Name Type Description
analyticsDays integerstring How many days of traffic this site's plan allows seeing, or zero when it includes none. Sent for the same reason as the flag above: the page can state what the plan covers instead of requesting the fi
analyticsExportAvailable boolean Whether this site's plan is sold with the traffic export. Read from the site's own plan rather than from the signed-in account's, because the two differ — an anonymous site is on the anonymous tier wh
anonymous boolean Whether the site has no account behind it. Stated rather than inferred, and it replaces an inference the dashboard was making from ExpiresAt being set. That proxy held only while an expiry meant one t
browserEditAvailable boolean Whether this site's plan lets its owner edit a file in the browser. Sent so the file list can leave the Edit action out rather than offering one the server refuses.
commentAudience string Who the owner chose may comment — `Off`, `Invited` or `Anyone`. The stored choice; it takes effect only where FeedbackAvailable is true and, for `Invited`, while the site is invite-only, which the Sha
createdAt string When the site was created.
customDomainAllowance integerstring How many hostnames of the customer's own this site's plan allows across the account, or zero when it includes none. Sent here rather than looked up from the public plans list, which is where the dashb
deploys array The most recent deploys, newest first.
docsMode boolean Whether the site is served through the documents viewer.
expiresAt nullstring When an unclaimed anonymous site is removed, or null once claimed.
expiryAction string What the expiry does when it falls due, `Pause` or `Delete`. Meaningless while ExpiresAt is null, and sent anyway so the form has something to show when the owner sets a date.
feedbackAvailable boolean Whether this site's plan includes comments. Sent for PasswordProtectionAvailable's reason: the control shows disabled with a reason rather than failing on submit.
folderId nullstring The folder it is filed in, or null when it sits at the root of the listing. The same field `SiteSummary` carries. Sent here as well so the site's own page can put that folder in its trail and return t
formerSubdomains array The names the site used to answer on, newest first, each redirecting to it.
formsAvailable boolean Whether the account's tier includes forms at all. Reported beside the switch for the reason PasswordProtectionAvailable is: the dashboard has to tell "off" apart from "not yours to turn on", and a con
formsEnabled boolean Whether the owner has switched form submissions on for this site.
invitedOnly boolean Whether only the people on the site's list may see it. Never true together with PasswordProtected.
invitedViewersAvailable boolean Whether this site's plan offers invite-only sites. Sent for PasswordProtectionAvailable's reason: the Sharing tab shows the third choice disabled with a reason rather than offering it and failing.
lastActiveAt string When it last received a deploy.
liveDeployId nullstring The deploy being served, or null.
maxSiteViewers integerstring How many people this site's plan lets the list hold, the owner included — and, per site, how many invitations it may mail in a day.
modeIsManual boolean Whether the serving mode was chosen by the owner rather than detected from the files of the deploy that went live. What lets the dashboard say which of the two it is showing.
name nullstring What to call it, or null when it has none and the subdomain should be shown instead. A label only. The site is reached by Subdomain whatever this says, which is why the dashboard shows the address und
openFeedback integerstring Threads open on the site, the number on the Feedback tab.
passwordProtected boolean Whether visitors must enter a password. Only whether one is set is reported — the password itself is stored as a hash, so there is nothing to return.
passwordProtectionAvailable boolean Whether this site's plan permits a password at all. Sent so the dashboard can show the control in a disabled state with a reason, rather than offering it and failing on submit.
planId string Plan whose limits apply.
primaryUrl string The URL to lead with: a hostname of the customer's own once one is serving, and Url otherwise. Sent as its own field rather than by overwriting Url, because the two are not interchangeable and the sub
publicDocumentCounts boolean Whether readers of this documents site see each document's views and downloads. Every plan may turn it on.
scheduledExpiryAvailable boolean Whether this site's plan lets its owner schedule when it comes down. Sent so the dashboard can show the control disabled with a reason rather than offering it and failing on submit.
siteId string ULID of the site.
spaMode boolean Whether an unmatched path falls back to index.html.
status string Whether the site is serving, and if not, who switched it off — the `SiteStatus` name. What the pause control reads, and what tells the three off-states apart for the customer. They need different word
statusChangedAt nullstring When the state last changed, or null if it never has.
subdomain string Its subdomain.
subdomainChangesLeft nullintegerstring How many more times the owner may change Subdomain, or null when the plan does not limit it. What the change-of-address control and its confirmation show.
trafficBreakdownAvailable boolean Whether this site's plan includes top lists, the globe and filters on the traffic page. Sent so the page draws a locked card naming the tier instead of requesting a list and rendering a 403.
trafficDetailAvailable boolean Whether this site's plan splits people from bots and AI and shows devices, browsers and campaigns.
url string Its public URL on the platform's own content domain.
View JSON Schema on GitHub

JSON Schema

dropto-run-site-detail-schema.json Raw ↑
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/dropto-run/json-schema/dropto-run-site-detail-schema.json",
  "title": "SiteDetail",
  "description": "Response of `GET /sites/{siteId}`.",
  "x-generated": "2026-11-06",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/dropto-run-openapi.json#/components/schemas/SiteDetail",
  "properties": {
    "analyticsDays": {
      "description": "How many days of traffic this site's plan allows seeing, or zero when it includes none. Sent for the\nsame reason as the flag above: the page can state what the plan covers instead of requesting the\nfigures and rendering a refusal.",
      "format": "int32",
      "pattern": "^-?(?:0|[1-9]\\d*)$",
      "type": [
        "integer",
        "string"
      ]
    },
    "analyticsExportAvailable": {
      "description": "Whether this site's plan is sold with the traffic export. Read from the site's own plan rather than\nfrom the signed-in account's, because the two differ — an anonymous site is on the anonymous tier\nwhoever is looking at it.",
      "type": "boolean"
    },
    "anonymous": {
      "description": "Whether the site has no account behind it.\n\nStated rather than inferred, and it replaces an inference the dashboard was making from\nExpiresAt being set. That proxy held only while an expiry meant one thing: now\nthat an owner can schedule a takedown on a site of their own, a paid site with a date on it would\nhave read as anonymous and been told it gets deleted after a few days.",
      "type": "boolean"
    },
    "browserEditAvailable": {
      "description": "Whether this site's plan lets its owner edit a file in the browser. Sent so the file list can leave\nthe Edit action out rather than offering one the server refuses.",
      "type": "boolean"
    },
    "commentAudience": {
      "description": "Who the owner chose may comment — `Off`, `Invited` or `Anyone`. The stored choice; it takes\neffect only where FeedbackAvailable is true and, for `Invited`, while the site is\ninvite-only, which the Sharing tab says in words.",
      "type": "string"
    },
    "createdAt": {
      "description": "When the site was created.",
      "format": "date-time",
      "type": "string"
    },
    "customDomainAllowance": {
      "description": "How many hostnames of the customer's own this site's plan allows across the account, or zero when it\nincludes none.\n\nSent here rather than looked up from the public plans list, which is where the dashboard read it and\nwhere it is not always findable: `GET /plans` filters to public tiers, so a site on a plan cut\nfor one account matched nothing and the section rendered as a heading with nothing underneath —\nexactly the account most likely to have been given an allowance. The same argument as\nPasswordProtectionAvailable, which is why it sits beside it.",
      "format": "int32",
      "pattern": "^-?(?:0|[1-9]\\d*)$",
      "type": [
        "integer",
        "string"
      ]
    },
    "deploys": {
      "description": "The most recent deploys, newest first.",
      "items": {
        "$ref": "#/$defs/DeploySummary"
      },
      "type": "array"
    },
    "docsMode": {
      "description": "Whether the site is served through the documents viewer.",
      "type": "boolean"
    },
    "expiresAt": {
      "description": "When an unclaimed anonymous site is removed, or null once claimed.",
      "format": "date-time",
      "type": [
        "null",
        "string"
      ]
    },
    "expiryAction": {
      "description": "What the expiry does when it falls due, `Pause` or `Delete`. Meaningless while\nExpiresAt is null, and sent anyway so the form has something to show when the\nowner sets a date.",
      "type": "string"
    },
    "feedbackAvailable": {
      "description": "Whether this site's plan includes comments. Sent for PasswordProtectionAvailable's\nreason: the control shows disabled with a reason rather than failing on submit.",
      "type": "boolean"
    },
    "folderId": {
      "description": "The folder it is filed in, or null when it sits at the root of the listing.\n\nThe same field `SiteSummary` carries. Sent here as well so the site's own page can put that\nfolder in its trail and return to it — after a removal, too — instead of to the root of the listing,\nwhich is where somebody who opened the site from inside a folder did not come from.",
      "type": [
        "null",
        "string"
      ]
    },
    "formerSubdomains": {
      "description": "The names the site used to answer on, newest first, each redirecting to it.",
      "items": {
        "$ref": "#/$defs/FormerSubdomain"
      },
      "type": "array"
    },
    "formsAvailable": {
      "description": "Whether the account's tier includes forms at all.\n\nReported beside the switch for the reason PasswordProtectionAvailable is: the\ndashboard has to tell \"off\" apart from \"not yours to turn on\", and a control that looks available and\nthen refuses is worse than one that says why.",
      "type": "boolean"
    },
    "formsEnabled": {
      "description": "Whether the owner has switched form submissions on for this site.",
      "type": "boolean"
    },
    "invitedOnly": {
      "description": "Whether only the people on the site's list may see it. Never true together with\nPasswordProtected.",
      "type": "boolean"
    },
    "invitedViewersAvailable": {
      "description": "Whether this site's plan offers invite-only sites. Sent for PasswordProtectionAvailable's\nreason: the Sharing tab shows the third choice disabled with a reason rather than offering it and failing.",
      "type": "boolean"
    },
    "lastActiveAt": {
      "description": "When it last received a deploy.",
      "format": "date-time",
      "type": "string"
    },
    "liveDeployId": {
      "description": "The deploy being served, or null.",
      "type": [
        "null",
        "string"
      ]
    },
    "maxSiteViewers": {
      "description": "How many people this site's plan lets the list hold, the owner included — and, per site, how many\ninvitations it may mail in a day.",
      "format": "int32",
      "pattern": "^-?(?:0|[1-9]\\d*)$",
      "type": [
        "integer",
        "string"
      ]
    },
    "modeIsManual": {
      "description": "Whether the serving mode was chosen by the owner rather than detected from the files of the deploy\nthat went live. What lets the dashboard say which of the two it is showing.",
      "type": "boolean"
    },
    "name": {
      "description": "What to call it, or null when it has none and the subdomain should be shown instead.\n\nA label only. The site is reached by Subdomain whatever this says, which is why\nthe dashboard shows the address underneath rather than replacing it: two sites are allowed the same\nname, and the name is not what anybody types into a browser.",
      "type": [
        "null",
        "string"
      ]
    },
    "openFeedback": {
      "description": "Threads open on the site, the number on the Feedback tab.",
      "format": "int32",
      "pattern": "^-?(?:0|[1-9]\\d*)$",
      "type": [
        "integer",
        "string"
      ]
    },
    "passwordProtected": {
      "description": "Whether visitors must enter a password. Only whether one is set is reported — the password itself is\nstored as a hash, so there is nothing to return.",
      "type": "boolean"
    },
    "passwordProtectionAvailable": {
      "description": "Whether this site's plan permits a password at all. Sent so the dashboard can show the control in a\ndisabled state with a reason, rather than offering it and failing on submit.",
      "type": "boolean"
    },
    "planId": {
      "description": "Plan whose limits apply.",
      "type": "string"
    },
    "primaryUrl": {
      "description": "The URL to lead with: a hostname of the customer's own once one is serving, and\nUrl otherwise.\n\nSent as its own field rather than by overwriting Url, because the two are not\ninterchangeable and the subdomain does not stop mattering: it needs no DNS of anybody's and keeps\nworking when a custom domain's records are changed or lapse, which makes it the address to fall back\nto when the other one is what is being diagnosed.",
      "type": "string"
    },
    "publicDocumentCounts": {
      "description": "Whether readers of this documents site see each document's views and downloads. Every plan may turn\nit on.",
      "type": "boolean"
    },
    "scheduledExpiryAvailable": {
      "description": "Whether this site's plan lets its owner schedule when it comes down. Sent so the dashboard can show\nthe control disabled with a reason rather than offering it and failing on submit.",
      "type": "boolean"
    },
    "siteId": {
      "description": "ULID of the site.",
      "type": "string"
    },
    "spaMode": {
      "description": "Whether an unmatched path falls back to index.html.",
      "type": "boolean"
    },
    "status": {
      "description": "Whether the site is serving, and if not, who switched it off — the `SiteStatus` name.\n\nWhat the pause control reads, and what tells the three off-states apart for the customer. They need\ndifferent words and different offers: their own pause has a button that undoes it, a suspension has\nsupport to contact, and being held for quota has an upgrade. One boolean could not say which.",
      "type": "string"
    },
    "statusChangedAt": {
      "description": "When the state last changed, or null if it never has.",
      "format": "date-time",
      "type": [
        "null",
        "string"
      ]
    },
    "subdomain": {
      "description": "Its subdomain.",
      "type": "string"
    },
    "subdomainChangesLeft": {
      "description": "How many more times the owner may change Subdomain, or null when the plan does not\nlimit it. What the change-of-address control and its confirmation show.",
      "format": "int32",
      "pattern": "^-?(?:0|[1-9]\\d*)$",
      "type": [
        "null",
        "integer",
        "string"
      ]
    },
    "trafficBreakdownAvailable": {
      "description": "Whether this site's plan includes top lists, the globe and filters on the traffic page. Sent so the\npage draws a locked card naming the tier instead of requesting a list and rendering a 403.",
      "type": "boolean"
    },
    "trafficDetailAvailable": {
      "description": "Whether this site's plan splits people from bots and AI and shows devices, browsers and campaigns.",
      "type": "boolean"
    },
    "url": {
      "description": "Its public URL on the platform's own content domain.",
      "type": "string"
    }
  },
  "required": [
    "siteId",
    "subdomain",
    "name",
    "folderId",
    "url",
    "primaryUrl",
    "liveDeployId",
    "spaMode",
    "docsMode",
    "modeIsManual",
    "passwordProtected",
    "passwordProtectionAvailable",
    "invitedOnly",
    "invitedViewersAvailable",
    "maxSiteViewers",
    "commentAudience",
    "feedbackAvailable",
    "openFeedback",
    "formsEnabled",
    "formsAvailable",
    "publicDocumentCounts",
    "analyticsDays",
    "trafficBreakdownAvailable",
    "trafficDetailAvailable",
    "analyticsExportAvailable",
    "scheduledExpiryAvailable",
    "browserEditAvailable",
    "anonymous",
    "expiryAction",
    "customDomainAllowance",
    "planId",
    "status",
    "statusChangedAt",
    "expiresAt",
    "createdAt",
    "lastActiveAt",
    "deploys",
    "subdomainChangesLeft",
    "formerSubdomains"
  ],
  "type": "object",
  "$defs": {
    "DeploySummary": {
      "description": "One deploy in a site's history.",
      "properties": {
        "completedAt": {
          "description": "When it reached a terminal state, or null while in flight.",
          "format": "date-time",
          "type": [
            "null",
            "string"
          ]
        },
        "createdAt": {
          "description": "When it was prepared.",
          "format": "date-time",
          "type": "string"
        },
        "deployId": {
          "description": "ULID of the deploy.",
          "type": "string"
        },
        "error": {
          "description": "Why it failed, when it did.",
          "type": [
            "null",
            "string"
          ]
        },
        "fileCount": {
          "description": "Files it holds.",
          "format": "int32",
          "pattern": "^-?(?:0|[1-9]\\d*)$",
          "type": [
            "integer",
            "string"
          ]
        },
        "filesKept": {
          "description": "Whether this version is inside the retention window with its files still on storage, and therefore\nwhether it can be previewed or rolled back to.\n\nIt is a field rather than something a client works out because it cannot be worked out from the rest\nof the response. `site.trim_deploys` keeps the plan's `retainedDeploys` most recently live\ndeploys, a rollback counting as going live, and deletes the objects of the rest, leaving the rows. A\nversion outside that window reads false at once, before the trim has run, because `promote`\nrefuses it by the same rule. The dashboard used to redraw that rule from a deploy's position in this\nlist, and disagreed with the server in both directions — and a plan whose retention was lowered then\nraised has versions inside the window whose files went weeks ago.\n\nstring DeploySummary.Status does not answer it either: a `superseded` deploy may be fully stored or\nentirely gone. Nothing about the row changes when its objects are deleted except this.",
          "type": "boolean"
        },
        "previewUrl": {
          "description": "URL serving this deploy on its own hostname, or null when there is no reachable preview of it.\n\nTwo reasons for null, and they are unrelated. The site's subdomain may be too long to leave room for a\npreview hostname (see int PreviewHostFormat.MaxSubdomainLength). Or the site's hostnames may\nnot be answering at all — see bool SiteLifecycle.HostnamesServe(Site site): a preview resolves through\nthe site's own hostname, so a tombstoned site has no reachable preview of any version, however sound\nthe deploy behind it is. A site an administrator restores is exactly that, and reporting a URL for it\nwas how the dashboard came to offer a history of versions none of which opened.\n\nIt works for any deploy whose files are still on storage, including one that was never published, and\nstops working once retention removes them — the same condition `promote` reports as a 410. Nobody\nis asked to log in: the URL is unlisted rather than access-controlled, and what protects it is the 80\nbits of randomness in a ULID. A password-protected site's previews are behind that password like the\nrest of it.",
          "type": [
            "null",
            "string"
          ]
        },
        "status": {
          "description": "Lowercase status name.",
          "type": "string"
        },
        "totalBytes": {
          "description": "Its size.",
          "format": "int64",
          "pattern": "^-?(?:0|[1-9]\\d*)$",
          "type": [
            "integer",
            "string"
          ]
        }
      },
      "required": [
        "deployId",
        "status",
        "fileCount",
        "totalBytes",
        "createdAt",
        "completedAt",
        "error",
        "previewUrl",
        "filesKept"
      ],
      "type": "object"
    },
    "FormerSubdomain": {
      "description": "One name a site used to answer on.",
      "properties": {
        "retiredAt": {
          "description": "When the site stopped answering on it.",
          "format": "date-time",
          "type": "string"
        },
        "subdomain": {
          "description": "The former subdomain, which redirects to the current one.",
          "type": "string"
        }
      },
      "required": [
        "subdomain",
        "retiredAt"
      ],
      "type": "object"
    }
  }
}

Work with this as data

Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for schemas

4 MCP tools reach this
  • find_json_schemasBrowse and filter every JSON Schema in the catalog.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/dropto-run-site-detail"
All schemas
curl "https://apis.io/api/v1/json-schemas?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.