Skip to main content

Show your space's posts on your own site

Render your public space's posts on a site you control — a marketing page, a blog, a landing page. Assumes your space has a public profile turned on.

1. Fetch the space (optional)

For your space's name, avatar, or links in the header:

curl https://api.dfos.com/v1/spaces/home

Address it by subdomain, entity id, or protocol DID. Store the id or did, not the subdomain — the subdomain is a mutable alias. See Spaces.

2. List the public posts

curl 'https://api.dfos.com/v1/spaces/home/posts?limit=20'

Posts come back newest first. Each item gives you a displayTitle (already handles untitled posts), an excerpt, a cover, counts, isPinned, and publishedAt. The feed does not reorder pinned posts; sort on isPinned yourself if you want them at the top. Page with nextCursor (see Conventions).

3. Link each post — or fetch its body

The listing does not include post bodies. Either fetch each post and link to its canonicalUri (the canonical public permalink, which respects the space's custom domain), or fetch it and render its body yourself. Fetch a single post by its id, not its slug:

curl https://api.dfos.com/v1/spaces/home/posts/post_ze2kh2d47tzerkhet8348c

The response is a union on state. Handle both arms:

async function renderPost(space, postId) {
const res = await fetch(`https://api.dfos.com/v1/spaces/${space}/posts/${postId}`);
if (res.status === 404) return null; // missing, private, or wrong space
const data = await res.json();

if (data.state === 'eligible') {
const post = data.post;
// post.folded === true means only the above-fold teaser is present;
// link to post.canonicalUri for the rest.
return { title: post.displayTitle, body: post.body, href: post.canonicalUri };
}

// data.state === 'gated' — no body; show a join / subscribe CTA.
// Treat an unrecognized data.reason as 'restricted'.
return { title: data.space.displayName, cta: data.reason, join: data.space.domain };
}
  • The gated arm carries no content. Render the space CTA — its domain, joinMode, and subscribeEnabled tell you how to prompt a join or subscribe — never a fake preview.
  • folded === true means the body is truncated at a fold. Show the teaser and link to canonicalUri; there is no anonymous way to fetch below-fold content.

4. Cache and stay compatible

  • Fetch fresh. Data responses are served Cache-Control: no-store; do not introduce your own shared cache of them, even when proxying. Watch the RateLimit-* headers and the 429 retry signal. See Rate limits and caching.
  • Tolerate growth. Ignore fields you don't recognize, and treat every enum (joinMode, siteMode, the gated reason) as open — new values can appear without a version bump. See the compatibility contract.
  • Store stable ids. Key your own storage on id / did, never on subdomains, handles, or slugs.

See Posts and Spaces for the full field semantics, and the interactive reference to try every endpoint.