Skip to main content

Compatibility and stability contract

This page is the stability contract: what the API guarantees stays the same over time, and what can change. For how to actually talk to the API today — pagination mechanics, the identifier forms you pass, reading errors — see Conventions.

The DFOS API is in beta. During the beta window the surface may still change. At general availability (GA) the contract becomes additive-only: existing fields and behavior are preserved, and changes arrive as new fields, new values, and new endpoints.

What clients must tolerate

Write clients that keep working as the API grows:

  • Unknown fields. Responses may gain new fields at any time, without a version bump. Ignore fields you do not recognize rather than failing on them.
  • Unknown enum values. Fields such as joinMode and siteMode may gain new values at any time, without a version bump. Handle unrecognized values gracefully instead of assuming a closed set.

Cursors

Pagination cursors (nextCursor, previousCursor) are opaque tokens. Store and return them unchanged — never parse, decode, or construct them. Their internal structure is not part of the contract and can change.

Identifiers

  • Entity ids (space_…, post_…, and similar) and protocol DIDs are canonical and stable. They identify the same entity for its lifetime.
  • Subdomains are mutable aliases. A space can change its domain, and a freed domain can later belong to a different space. A subdomain you stored may silently begin resolving to a different space.

Store entity ids or protocol DIDs when you need a durable reference. Use subdomains only for display and links.

DIDs on the wire

Decentralized identifiers in API responses are protocol DIDs — did:dfos: followed by 31 characters. Treat them as opaque, stable identifiers.

Media URLs

Media objects come back in two URL classes, and every media object tells you which it is:

  • Public images (post covers, avatars, inline body images) resolve to a permanent, unsigned CDN URL. These carry no urlExpiresAt.
  • Private media (audio, video, and other file attachments) resolve to a time-limited signed URL, returned inline on the post response. These carry a urlExpiresAt timestamp marking when the URL stops working, and its presence is the signal that the URL is signed and expiring.

Never persist a signed URL (any media url / playbackUrl accompanied by urlExpiresAt). Re-fetch the post to obtain fresh URLs when you need them — data responses are not cached (see Rate limits and caching), so a fresh fetch always returns fresh URLs.

Even a permanent public URL is stable only while the media remains referenced by public content: these are not archival URLs. If the underlying content is removed or the reference is dropped, the URL can stop resolving. Re-fetch media URLs from the API rather than treating any of them as durable.

Errors

Error responses are machine-readable and documented in the OpenAPI specification. Read the response body's error fields rather than relying only on the HTTP status.