Sites

Get a site by id or slug.

Same viewer-number gating as the list endpoint: metrics_locked, plus opened on every plan. Also carries badged, the per-page answer to whether this page shows the "Made with Stacktree" footer, which the plan alone does not decide.

get/sites/{idOrSlug}

Request

  • Base URL: https://api.stacktr.ee
  • URL: https://api.stacktr.ee/sites/{idOrSlug}
  • Auth: one of:
    • HTTP bearer
    • OAuth 2 (authorization code, authorization URL https://api.stacktr.ee/oauth/authorize, token URL https://api.stacktr.ee/oauth/token, scopes: sites:write, sites:read)

Response

OK

idstring required

Stable site identifier.

slugstring nullable

Public subdomain slug, if the site is public.

visibility'unlisted' | 'public' | 'burn' required

Privacy mode.

urlstring uri

Canonical URL to view the site.

created_atinteger required

Unix epoch seconds.

updated_atinteger

Unix epoch seconds.

expires_atinteger nullable

Unix epoch seconds; null = no expiry. Clamped to the plan ceiling at write time (Free: 7 days, anonymous: 24 hours), so this can come back sooner than you asked for.

expires_at_isostring nullable

The same instant as expires_at, RFC 3339 UTC, second granularity (e.g. "2026-09-08T12:00:00Z"). Present so a client can show a deadline without reconstructing it from the epoch.

ttl_secondsinteger nullable

Seconds from now until the page stops serving. Null when it does not expire; 0 when it is already out of time. Never negative.

expiry_clampedboolean

True when the lifetime THIS request asked for was longer than the plan allows and expires_at is the shortened reality. Always present, false included. False on reads, which ask for no lifetime. Asking for a page that never expires on a capped plan is refused (409 expiry_clamped) rather than clamped, unless accept_clamp is sent.

expiry_ceiling_hoursinteger nullable

The longest lifetime this plan allows a page, in hours: 24 anonymous, 168 on Free, null on plans with no ceiling and on the paid one-off rails.

expiry_source'request' | 'plan_ceiling' | 'plan_default' | 'stored'

What decided the date: request (the caller named it), plan_ceiling (the plan cap did), plan_default (the plan default did), or stored (this call only read the row).

byte_sizeinteger

Total content size in bytes.

metrics_lockedboolean

True when the plan has no viewer numbers (anonymous and Free). The three viewer fields below are then null; there is no number to reveal, blur, or approximate.

openedboolean

Whether anyone has opened the page. Returned on every plan, including when metrics_locked is true, so "someone read this" survives the lock.

badgedboolean

Whether THIS page carries the "Made with Stacktree" footer as served on its stacktr.ee URL. Returned by GET /sites/{idOrSlug} only. A fact about the page, not about the plan: pages published before 2026-08-03, generated client portals and end-to-end encrypted pages carry no badge even on Free, and a remove_badge entitlement lifts it off one page or a whole account. Never assume it from the plan; anything offering to remove the badge should read this.

view_countinteger nullable

Raw view count. Null when metrics_locked.

unique_viewersinteger nullable

Distinct human viewers over the last 30 days. Null when metrics_locked.

last_viewed_atinteger nullable

Unix epoch seconds of the most recent open. Null when metrics_locked, or when never opened.

client_urlstring

Present on publish when the space has a connected hostname and the page got a space_path: the page’s address on the client’s own domain (e.g. https://acme.theiragency.com/june-report). Prefer handing this link to the user.

claim_tokenstring nullable

Anonymous publishes only. Adopts the page into an account (POST /sites/{idOrSlug}/claim) and, until then, is its keyless update credential. As sensitive as the page.

claim_urlstring uri

Anonymous publishes only. The dashboard claim screen for this page: sign in, and the page moves into that account at the same address.

keep_urlstring uri

Anonymous publishes only. Give this to the person you published for: it opens a page that says when this page stops working and offers both ways to keep it (a free account, or the link by email); opening it keeps nothing until they choose one. It also marks their browser so the page itself shows them a Keep button. It carries the claim token, so it is as sensitive as claim_url: share url, never this.

deleted_atinteger nullable

Unix epoch seconds the page stopped serving; null when it is live. Non-null means the URL is dead for everyone holding it.

delete_reasonstring nullable

Why it stopped serving: expired, owner (someone deleted it), abuse (a takedown), or merged (folded into another page; see merged_into). null while the page is live. abuse and merged are never restorable: POST /sites/{idOrSlug}/restore refuses them, so do not offer a restore control for either.

restorable_untilinteger nullable

Unix epoch seconds. A real deadline, not a hint: the hourly cleanup destroys the content at that moment and restore returns 404 from then on.

Changes

No recorded changes to this operation across all 1 revision of this API.