Add an activity to a feed
const url = 'http://localhost:3000/v1/feeds/example/example/activities';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"actor":"example","verb":"example","object":"example","target":"example","foreign_id":"example","time":"2026-04-15T12:00:00Z","custom":{},"refs":["example"]}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url http://localhost:3000/v1/feeds/example/example/activities \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "actor": "example", "verb": "example", "object": "example", "target": "example", "foreign_id": "example", "time": "2026-04-15T12:00:00Z", "custom": {}, "refs": [ "example" ] }'Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Request Bodyrequired
Section titled “Request Bodyrequired”object
Ignored and overwritten for user tokens (spec §5).
Requires time when present — VALIDATION_FAILED otherwise. Dedupe is on the
(foreign_id, time) pair; a foreign_id without a caller-pinned time can never
dedupe (each retry would get a fresh server timestamp, silently duplicating),
so the API rejects the combination rather than letting an idempotency
assumption fail quietly. Deliberate safety deviation from GetStream.
For user tokens, clamped to [now - 10 min, now] (spec §5): retries with the same (foreign_id, time) dedupe; future-pinning is impossible. Server tokens pass it through unclamped. Required when foreign_id is set.
object
Objects this activity points at, as type:id. Max 4, no duplicates.
Examplegenerated
{ "actor": "example", "verb": "example", "object": "example", "target": "example", "foreign_id": "example", "time": "2026-04-15T12:00:00Z", "custom": {}, "refs": [ "example" ]}Responses
Section titled “Responses”Created — or, on a (foreign_id, time) duplicate of a live activity, the existing row unchanged (idempotent, no second fan-out).
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.
Example
{ "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" ]}Invalid, expired, revoked, or absent token.
object
object
Present only for VALIDATION_FAILED.
object
Example
{ "error": { "code": "VALIDATION_FAILED" }}Authenticated but not permitted.
object
object
Present only for VALIDATION_FAILED.
object
Example
{ "error": { "code": "VALIDATION_FAILED" }}The (foreign_id, time) identity belongs to a soft-deleted activity. The identity is burned — pick a new one (spec §6).
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" }}