Search the complete documentation

Try idempotency, proposal lifecycle, authentication, or ordering.

Navigate Open
繁體中文
Browse documentation

Activity · Visibility

Visibility and host-owned policy

Activity enforces reusable feed visibility from the signed tenant and actor context. Your host still decides whether a user may publish, follow, block, report, or act as a particular actor before it signs the request.

Host authorization
  └─ may this user perform this product action?

Activity enforcement
  └─ is this post visible to this signed actor now?

Activity cannot recover business roles, subscription state, organization membership, or object permissions from an actor_id.

Post visibility

Set visibility when publishing a post:

ValueAuthorActive followerOther actor in tenantFollower fan-out
publicVisibleVisibleVisibleYes
followersVisibleVisibleNot visibleYes
privateVisibleNot visibleNot visibleNo

Visibility applies after tenant isolation. A public post is public inside its Activity tenant, not across tenants.

The current post update contract can change body, metadata, and render_refs. It does not expose a visibility transition. Choose visibility at publish time.

Profile and home reads

The home timeline reads materialized entries for the signed actor, then applies current deletion, moderation, hide, mute, and block filters.

The profile endpoint evaluates visibility when it reads the source posts:

GET /api/v1/actors/{actor_id}/posts

An author can read their own visible posts. Another actor sees public posts plus follower-only posts when an active follow exists. Private posts remain author-only.

Both endpoints return an empty result when no posts are visible. A post-level action that cannot see its target returns post_not_found, so the response does not disclose whether a hidden or inaccessible post exists.

Follow and unfollow

Following creates or reactivates an edge from the signed actor to followed_id:

POST /api/v1/follows
Content-Type: application/json

{ "followed_id": "actor-b" }

The edge enables follower visibility and future follower fan-out. It does not backfill older posts into the home timeline immediately.

Unfollow deletes the edge and removes existing following entries from that author’s posts. It does not delete the source posts.

Mute

Mute changes the caller-to-target relationship state to muted and removes that target’s existing entries from the caller’s timeline:

POST /api/v1/relationships/{actor_id}/mute

Muted posts are also excluded from profile reads by the muted viewer. Mute is directional. It does not prevent the other actor from reading or following the caller.

The current unmute operation restores the relationship state to active:

DELETE /api/v1/relationships/{actor_id}/mute

That is the current contract, even when the relationship was not previously an active follow. Consumers should not model mute as an independent preference flag.

Block

Block creates a blocked relationship from the caller to the target. Activity then:

  • removes existing timeline entries between both actors
  • prevents either direction from reading the other’s profile posts
  • prevents new follows while either direction has a block edge
  • excludes future follower fan-out across the blocked pair
POST /api/v1/relationships/{actor_id}/block

Unblock deletes the caller’s block edge. It does not restore previous follows or timeline entries:

DELETE /api/v1/relationships/{actor_id}/block

Hide

Hide is scoped to one viewer and one post:

POST /api/v1/posts/{post_id}/hide

Activity records the hidden pair and removes the post from that viewer’s materialized timeline. Other viewers and the source post are unchanged. A rebuild continues to exclude the hidden post.

The hidden pair has a database uniqueness constraint. After hiding, the post is no longer visible to that viewer, so repeating the endpoint returns post_not_found instead of creating another record. The public contract does not currently expose an unhide operation.

Report and moderation

Report records one report per tenant, post, and actor:

POST /api/v1/posts/{post_id}/reports
Content-Type: application/json

{
  "reason": "host-policy-code",
  "metadata": { "case_id": "case_1842" }
}

Repeating the report updates its reason and metadata. Activity also writes a post.reported outbox event.

Reporting does not hide the post, change moderation_state, or decide a moderation outcome. The current public API has no moderation transition, review queue, report export, restore, or webhook delivery contract. The host owns those decisions and workflows.

Responsibility matrix

Decision or stateOwner
Which tenant and actor the caller may representHost
Whether the user may publish or followHost
Post visibility enum and graph enforcementActivity
Hide state for one viewer and postActivity
Report record and outbox eventActivity
Report review and moderation decisionHost
Product ranking and recommendation policyHost
Rendering host objects and media referencesHost

Current gaps

Protected accounts and follow requests are not modeled. Visibility cannot be changed after publish through the public API. Reports have no public review or delivery workflow. The moderation state field exists, but hosts cannot transition it through /api/v1.

Treat these as product gaps, not implied extension points.

Next: inspect the Activity HTTP operation index.