Skip to main content

Conventions

How to talk to the DFOS API today: the behavior shared across every resource — pagination, identifiers, and errors. Read this once; the resource pages assume it. For what's guaranteed to stay stable versus what can change over time, see the compatibility contract.

Pagination

The list endpoints (GET /v1/spaces, GET /v1/spaces/{space}/pages, GET /v1/spaces/{space}/posts, GET /v1/spaces/{space}/topics, GET /v1/users) use cursor pagination:

  • limit sets the page size. The default is 20; the minimum is 1 and the maximum is 100.
  • Pass the response's nextCursor as after to fetch the next page.
  • Pass the response's previousCursor as before to fetch the previous page.
  • Do not send after and before together.
  • A null cursor means there is no page in that direction.

When a listing accepts filters or a sort order, hold them constant for the entire pagination walk. Cursors do not encode those inputs; changing them mid-walk can skip or repeat items.

curl 'https://api.dfos.com/v1/spaces?limit=20&after=eyJpZCI6InNwYWNlXzdneDRrMm05In0'

totalCount is the total number of matching items when the endpoint computes it. It is optional — it may be null or absent entirely, so treat it as a hint and never require its presence.

Cursors are opaque. Store and return them unchanged; never parse, decode, or construct one. Their internal encoding carries no stability guarantee and can change (see the compatibility contract).

Identifiers

Every resource is addressable by a stable identifier and, where it exists, by a mutable alias:

ResourceStable (store these)Mutable alias (display / links only)
Spaceentity id (space_…), protocol DIDsubdomain (domain)
Userentity id (identity_…), protocol DIDhandle (username)
Postentity id (post_…)slug
Pageid (page_…)slug

The stable identifiers point at the same entity for its lifetime. A mutable alias can change or be released, and a released alias can later resolve to a different entity — so never key your own storage on a subdomain, handle, or slug. Legacy internal identifiers are never accepted and return 404 Not Found.

DIDs on the wire

Every did in a response is a protocol DIDdid:dfos: followed by 31 chain-derived characters (40 characters total). It is the only DID form this API speaks. Treat DIDs as opaque, stable identifiers; resolve them against the relay from GET /v1/protocol.

Errors and not-found

Errors are machine-readable — read the response body's error fields rather than relying only on the HTTP status. 429 and 503 are covered under Rate limits and caching.

A 404 Not Found is deliberately ambiguous: a private, missing, or unknown-identifier resource all return the same 404, so an anonymous caller can never distinguish "you can't see this" from "this doesn't exist." The full model is in Content visibility.

Stability

New fields, new enum values, and new endpoints can arrive without a version bump; existing fields and behavior are preserved once the API reaches general availability. Write clients that ignore unknown fields and tolerate unknown enum values — the full rules are in the compatibility contract.