deed.page

Blog · 2026-10-01

Opt-in TTLs for throwaway agent pages

deed.page defaults to permanent hosting. The first anonymous publish does not expire, and there is no claim window. That is the right default for reports, dashboards, and anything an agent wants to link later. Sometimes you still want the opposite: a preview that should disappear after a review window, a CI artifact that should not sit forever, or a debug dump that should not consume a Free plan slot after the day ends.

For those cases the API accepts an opt-in TTL. Omit it and the site stays permanent. Set it and the response includes expires_at; after that time the slug stops serving.

REST: X-Ttl or ?ttl=

TTL is a positive number of seconds. Pass it as the X-Ttl header or the ttl query parameter. Either form works with PUT or POST.

A one-hour HTML preview:

curl -sS -T preview.html \
  "https://deed.page/v1/sites?slug=ci-preview-$(date +%Y%m%d-%H%M)" \
  -H "X-Ttl: 3600"

Or a JSON file map with a 24-hour window:

curl -sS -X POST "https://deed.page/v1/sites?ttl=86400" \
  -H 'content-type: application/json' \
  -d '{
    "slug": "agent-scratch",
    "files": {
      "index.html": "<!doctype html><h1>scratch</h1><p>auto-expires</p>"
    }
  }'

Typical success fields: ok, url (for example https://agent-scratch.deed.page/), path_url, version, permanent (false when TTL is set), expires_at (ISO-8601), bytes, files, and — on the first anonymous publish only — token. Store that deed_tok_… value; updates and deletes still need it even when the site is temporary.

Invalid values (zero, negative, or non-numeric) return 400 with code bad_request and the message that X-Ttl must be a positive number of seconds.

MCP: ttl_seconds on publish_site

The Streamable HTTP MCP server at https://deed.page/mcp exposes the same option as ttl_seconds on publish_site and update_site:

{
  "name": "publish_site",
  "arguments": {
    "slug": "pr-42-preview",
    "ttl_seconds": 7200,
    "files": {
      "index.html": "<!doctype html><h1>PR 42</h1>"
    }
  }
}

Omit ttl_seconds for a permanent site. The tool response mirrors REST: permanent, expires_at, and the one-time token when you published anonymously.

What happens when it expires

After expires_at, GET on the public URL and get_site behave as if the slug is gone (404 / not_found). Listing with your Bearer token skips expired sites. You can delete early with DELETE /v1/sites/{slug} (or MCP delete_site) if you no longer need the URL.

A later publish to the same slug with your token can set a new TTL, clear expiry by omitting TTL (the site becomes permanent again), or replace the files. Treat TTL like any other publish field: send what you want the slug to be after this request.

Patterns that fit agents

What TTL is not

Related

Questions or corrections: ops@avatar33.com.