Read a feed, enriched
const url = 'http://localhost:3000/v1/feeds/example/example?limit=20';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url 'http://localhost:3000/v1/feeds/example/example?limit=20' \ --header 'Authorization: Bearer <token>'Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Query Parameters
Section titled “Query Parameters”Deprecated alias for next. next wins if both are sent.
Opaque paging token. Pass the next value from the previous page.
Responses
Section titled “Responses”A page of activities, reverse-chronological. On an uncursored
request the page also carries the promoted sidecar.
object
Opaque cursor. Null when no further page.
object
object
object
Enriched from users.custom when actor parses as user:
Omitted for server tokens — no caller identity.
Objects this activity points at, as type:id. Resolved into the feed
read’s objects sidecar. Max 4, no duplicates.
Null until the activity is first patched.
Row version. Starts at 1 and increments on ANY change to this activity — a
patch, a reaction count moving, a soft delete. Compare it against the copy
you hold to decide whether to re-render; edited_at marks patches only, so
it cannot report the field that changes most.
Non-fatal problems with the activity that was just WRITTEN. Present only on
the response to POST /v1/feeds/{group}/{id}/activities; a feed read never
carries it — the read path stays exactly three statements.
actor_user_unresolved: the write succeeded, but actor names a user:<id>
with no users row, so actor_user is null and every card renders with no
name and no avatar until that user is upserted. Without this field a correct
write and a broken one are byte-identical. A non-user: actor
(system:jobs) never enriches by design and is NOT warned about.
Promoted activities this caller is eligible for. Present ONLY when the request carried no cursor/next — absent (not empty) on every subsequent page, so one delivery per feed open needs no server-side state. These rows are NOT in results and never affect next: the cursor is a position in the real feed, and a promoted row shifting it would skip or repeat real activities. This is the eligible set, not a slot assignment — cache it client-side and place it as often as you like (see the react SDK’s promotedPosition / promotedRepeatEvery).
A promoted activity as delivered in a feed read’s promoted sidecar. Activity-shaped so the same render path works, but it is NOT an activity: it has no time, no origin_feed, no reactions, and it was never fanned out to anyone’s feed. Targeting fields (audience) and counters (served_count) are deliberately absent here — exposing the audience would leak the tenant’s segmentation to end users.
object
object
Always true. Present so a merged render path can branch on it.
Refs on this page, resolved. Keyed by type:id. ABSENT (not
empty) when no activity on the page carries a ref — the same
absent-vs-empty convention as promoted. A ref with no stored
object is simply missing from the map, not an error.
object
Tenant-owned mutable data that activities point at. Opaque to dropin — we
store, update, and return custom, and never interpret it. Writes are
server-token only.
object
object
Example
{ "results": [ { "actor": "user:alice", "verb": "post", "object": "workout:123", "origin_feed": "user:alice", "reaction_counts": { "like": 3 }, "own_reactions": [ "like" ], "refs": [ "session:1234" ], "warnings": [ "actor_user_unresolved" ] } ], "promoted": [ { "actor": "system:fcurban", "verb": "promote", "object": "game:8842", "promoted": true } ], "objects": { "additionalProperty": { "type": "session", "id": "1234" } }}Invalid, expired, revoked, or absent token.
object
object
Present only for VALIDATION_FAILED.
object
Example
{ "error": { "code": "VALIDATION_FAILED" }}Rate limit exceeded.
object
object
Present only for VALIDATION_FAILED.
object
Example
{ "error": { "code": "VALIDATION_FAILED" }}