Activity and mailbox delivery

Fetch relationship events for display or delivery and acknowledge each event explicitly after your application reaches its chosen durable delivery point. The receipt means your application reported delivery; it does not independently prove a human read the message.

Routes and authority

All routes use POST under https://api.relationship.service.m7.org/v1/ and require the Bearer and workspace contract.

Route Required fields Optional fields Capability and result inside data
/projects/activity/list project_id subject_type, space_id, subspace_id, count, offset relationship.list; project_id, items, next_offset.
/mailbox/list project_id principal, subject_type, space_id, subspace_id, search, state, count, offset mailbox.notifications; mailbox page.
/mailbox/view project_id, principal Same list filters except principal is required mailbox.notifications; mailbox page.
/mailbox/ack project_id, principal, entry_id — mailbox.notifications; project_id, entry_id, principal, acknowledged_at.

All IDs are non-nil UUID strings. principal uses the exact namespace and principal_id object. Your application must authenticate its user and select the correct principal. Knowing a recipient ID does not establish the user's authority.

Filters and page results

Field Contract
subject_type space, subspace, relationship, invitation, application or connection; omit for all types.
space_id, subspace_id Optional exact ID filters; omission leaves that dimension unfiltered.
search Mailbox-only UTF-8 string, at most 255 bytes; case-insensitive literal substring, trimmed before use. Empty means no search.
state Mailbox-only all, unacknowledged or acknowledged. /list defaults to all; /view defaults to unacknowledged. Without a principal only all is valid.
count, offset Integer count 1–200 and nonnegative offset at most PHP_INT_MAX - 201. Mailbox defaults: 50/0; activity defaults: 100/0.

Mailbox pages return project, project_id, nullable principal, items, integer total_count, boolean has_more and nullable next_offset. Filters apply before pagination and counting. Activity pages omit total count.

An event includes id, project_id, nullable scope IDs, subject_type, subject_id, action, nullable actual actor, occurred_at, created and snapshot. The snapshot holds before, after, space and subspace; removed relationships also have removal attribution and reason. Principal-filtered mailbox items add nullable acknowledged_at.

Principal filtering matches the exact namespace and UUID in source/target references from before/after snapshots. It selects relationship and enrollment events involving that principal. An actor field alone does not address an event to that actor. Project-wide lists also include scope-management events.

curl --fail-with-body --silent --show-error \
  --request POST 'https://api.relationship.service.m7.org/v1/mailbox/view' \
  --header 'Authorization: Bearer ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{"project_id":"PROJECT_UUID","principal":{"namespace":"example.app","principal_id":"PERSON_UUID"},"state":"unacknowledged","count":50,"offset":0}'

Acknowledge after delivery

curl --fail-with-body --silent --show-error \
  --request POST 'https://api.relationship.service.m7.org/v1/mailbox/ack' \
  --header 'Authorization: Bearer ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{"project_id":"PROJECT_UUID","principal":{"namespace":"example.app","principal_id":"PERSON_UUID"},"entry_id":"ENTRY_UUID"}'

Ack handles one entry per call and records the first acknowledgement time. Repeating it keeps the original acknowledged_at. Pairwise participants have independent receipts. A missing, foreign or unrelated recipient entry returns body code 404; current caller admission and project authority are rechecked during the mutation.

Mailbox fetches and previews do not acknowledge or expire requests. Acknowledge only when the consumer's chosen delivery step is complete. Activity reads can settle expired enrollment requests and append their outcome events.

Offset delivery loops

Acknowledging a page removes its entries from an unacknowledged filtered set. Do not then follow that page's old next_offset, which can skip messages. Drain from offset zero after each acknowledged page, or finish a fetch pass before acknowledging it. Deduplicate by event ID because new events can shift offsets. Delivery is not a cursor or exactly-once protocol.

Use current relationship records for current access decisions. An event is a historical fact, including after removal or scope deletion. Your application curates its presentation and any email, webhook or permission effects.