API docs

zpe-screens

mount /screens · base https://zpe.vc/screens · v1.0.1 · 2 operations · 1 write · 0 need no account · wip

the document this app serves now. Contract: https://zpe.vc/screens/_/api/v1/openapi.json · sha256 e2356be5b7e0

GET /_/api/v1/screens Search captures by the text on the page, host, path and time getScreens

Search captures by the text on the page, host, path and time

Parameters

nameinrequiredtypenotes
hostquerynostringA host as the app registry spells it, e.g. `zpe.vc`.
limitquerynointegerHow many rows to return, 1 to 200. Defaults to 50, newest first.
pathquerynostringThe page's path, starting with `/`. Exact match, so two captures of the same page are one timeline.
qquerynostringWords to match against the rendered text. Every word must appear, and each one matches as a prefix. FTS5 operators cannot survive the parser, so a search is words and not a query language.
sincequerynostringOnly captures at or after this instant: epoch milliseconds or an ISO date.

Request body

None: this operation takes its arguments in the path and the query.

Responses

statusmeaningbody
200The captures the question names, newest firstobject
400The query string could not be read: `q` held no words, `host` or `path` was malformed, `since` was not a date, or `limit` was outside 1 to 200object
401No key and no door session was sent, or the key sent does not open this accountobject
403The key is not granted this app for reads, or the door named no account to scope the read toobject
429This key has spent its request ceiling; the refusal says when to retryobject
500This app failed while answeringobject
503The door did not answer, so the credential could not be checkedobject

Example

Search captures by the text on the page, host, path and time, with a token from the door.

GET /_/api/v1/screens
curl -X GET 'https://zpe.vc/screens/_/api/v1/screens?host=string&limit=0&path=string&q=string&since=string' \
  -H 'Authorization: Bearer $ZPE_TOKEN'
200 application/json
{
  "query": {
    "q": null,
    "host": null,
    "path": null,
    "since": null,
    "limit": 0
  },
  "count": 0,
  "rows": [
    {
      "id": 0,
      "host": "string",
      "path": "string",
      "final_url": null,
      "viewport": "string",
      "commit_id": "string",
      "deploy_id": "string",
      "captured_at": 0,
      "captured_at_iso": "2026-10-31T09:00:00Z",
      "sha256": "string",
      "image_bytes": 0,
      "image_url": "string",
      "text_excerpt": "string",
      "text_length": 0,
      "previous": null,
      "changed_since_previous": null,
      "match_snippet": "string"
    }
  ]
}

The example is generated from the schema in the contract: the shape is the document's, the values are placeholders.

POST /_/api/v1/screens Store one capture, bound to the commit it came from postScreens

Store one capture, bound to the commit it came from

Parameters

No parameters.

Request body application/json · required

fieldtyperequirednotes
imagestringyesThe image as a data URL (`data:image/webp;base64,…`) or bare base64. The R2 object key is the sha256 of these bytes, so a second identical capture costs no second object.
content_typestringnoThe image's type. Defaults to the data URL's, or `image/webp`.
hoststringyesThe host the page was served from, lower case, no scheme and no path.
pathstringyesThe page's path on that host. Must start with `/`; the first capture of a path compares against nothing.
commitstringyesThe full commit the page was deployed from. REQUIRED: a capture with no commit cannot answer "what did this page say before this change", and the route refuses it by name.
viewportstringyesThe capture's viewport, `<width>x<height>`, e.g. `1440x900`.
textstringnoThe page's rendered text. The whole of it is indexed for search; the row carries an excerpt.
deploy_idstringnoThe deployment's id, when the sweep knows it.
final_urlstringnoWhere the browser ended up. The sweep refuses a `/build` landing rather than storing it.
captured_atinteger | stringnoWhen the capture was taken: epoch milliseconds or an ISO date. Defaults to now.

Responses

statusmeaningbody
200The library already held this capture, and answers the row it holdsobject
201A new capture was storedobject
400The request could not be readobject
401The credential is missing or does not open this accountobject
403This account may not do thatobject
404Nothing is hereobject
429Too many requestsobject

Example

Store one capture, bound to the commit it came from, with a token from the door.

POST /_/api/v1/screens
curl -X POST 'https://zpe.vc/screens/_/api/v1/screens' \
  -H 'Authorization: Bearer $ZPE_TOKEN' \
  -H 'content-type: application/json' \
  -d '{
  "image": "string",
  "content_type": "string",
  "host": "string",
  "path": "string",
  "commit": "string",
  "viewport": "string",
  "text": "string",
  "deploy_id": "string",
  "final_url": "string",
  "captured_at": null
}'
200 application/json
{
  "id": 0,
  "sha256": "string",
  "r2_key": "string",
  "image_bytes": 0,
  "captured_at": 0,
  "object_written": false,
  "row_created": false
}

The example is generated from the schema in the contract: the shape is the document's, the values are placeholders.