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
spaceCTA — itsdomain,joinMode, andsubscribeEnabledtell you how to prompt a join or subscribe — never a fake preview. folded === truemeans the body is truncated at a fold. Show the teaser and link tocanonicalUri; 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 theRateLimit-*headers and the429retry signal. See Rate limits and caching. - Tolerate growth. Ignore fields you don't recognize, and treat every enum
(
joinMode,siteMode, the gatedreason) 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.