{"id":"linked-art/activity-stream-profile","relativePath":"linked-art/activity-stream-profile.md","title":"MetaMuseum Linked Art Activity Stream Profile","markdown":"# MetaMuseum Linked Art Activity Stream Profile\n\nLast updated: 2026-07-07\n\nMetaMuseum exposes `/api/activity` as an ActivityStreams 2.0 change feed with an embedded Linked Art projection on each activity item. The feed is designed for downstream collection-data consumers that need incremental synchronization while preserving Linked Art event semantics.\n\n## Endpoints\n\n| Endpoint | Purpose |\n|---|---|\n| `/api/activity` | Global ActivityStreams `OrderedCollectionPage` over local write-audit, deletion, and semantic record activities. |\n| `/api/activity/collection` | IIIF Change Discovery-compatible `OrderedCollection` with mandatory `first` and `last` page references. |\n| `/api/activity/page/{page}` | Fixed ascending `OrderedCollectionPage` resources for walk-back harvesters. |\n| `/api/activity/object/{encodedObjectId}` | Object-scoped `OrderedCollectionPage` for one Linked Art object URI. |\n| `/api/activity/readiness` | External-consumer readiness ledger populated by declared feed reads. |\n| `/api/activity/subscriptions` | Durable callback subscription registry and verification target for downstream aggregators. |\n| `/api/providers/capabilities` | Provider and activity-syndication capability document, including discovery rels, endpoint templates, filters, and callback signing headers. |\n\nAll activity endpoints support `GET` and `OPTIONS`, CORS, and `application/activity+json`.\n\n## Item Shape\n\nEach `/api/activity` cursor-feed `orderedItems[]` entry is an ActivityStreams activity with:\n\n- `type`: `Create`, `Update`, or `Delete`\n- `endTime`: valid UTC synchronization timestamp; original invalid source times are retained under `extensions.sourceEndTime`\n- `object`: the affected object or tombstone, including dereferenceable `id`, optional `sourceId`, `activityHref`, and optional `equivalent[]` reconciliation links\n- `source.kind`: `audit`, `record-backfill`, `record-semantic`, or `deletion`\n- `linkedArt`: a Linked Art JSON-LD projection with `@context: https://linked.art/ns/v1/linked-art.json`; embedded `linkedArt.id` values dereference through `/api/events/{encodedSourceActivityId}`, carry `_complete: false`, and preserve source activity identity in `equivalent[]` when available\n\nFor semantic collection events, `linkedArt` preserves event-centric fields such as `type`, `timespan`, `_complete`, names, classifications, object-specific target links (`produced`, `created`, `modified`, `destroyed`, `removed`, `encountered`, `formed`, `dissolved`), `used_specific_object`, and `carried_out_by` when those fields are valid for the activity class. `Set` collection records emit `Creation`/`created` rows, not physical `Production` rows, and record detail responses preserve `member_of` on the member record rather than inventing inverse `member[]` lists on the Set. Provenance wrapper activities also preserve relative `before`/`after` ordering and bundled `part[]` entries such as `Encounter`, `Acquisition`, `RightAcquisition`, `TransferOfCustody`, indeterminate `Transfer`, `Move`, and `Payment`, including nested find/rediscovery, title-transfer, rights-establishment/invalidation, percentage ownership shares, copyright, custody-transfer, unknown-transfer, movement origin/destination, multiple-owner, agent, exchange, loan, theft/loss, and commission/service payment details. Auction activities preserve auction-house/place classifications, auction-of-lot identifiers, lot `Set` `used_specific_object` values, `part_of` links to the overall auction, and provenance purchases `caused_by` the lot auction. Exhibition activities preserve exhibiting classifications, venue and organizer metadata, source descriptions, object-list `Set` links, concept `PropositionalObject` influence, and travelling-exhibition `part_of` links. Conservation coverage keeps condition assessments as `AttributeAssignment` rows with `assigned_property` and `assigned` condition types, separate from conservation `Modification` rows with technique, actor, description, timespan, and shared project `part_of` links. `Birth` and `Death` projections intentionally suppress `carried_out_by` and `used_specific_object`, matching the Linked Art activity-class restrictions.\n\nDefault `/api/activity` cursor-feed responses and IIIF Change Discovery pages use the same partner-facing projection: valid UTC `endTime`, dereferenceable MetaMuseum `object.id` values, optional `object.sourceId` with the stored/provider record id when the projected id differs, `object.activityHref`, `source.kind`, and provider metadata. Default responses collapse duplicate rows for the same projected `object.id` to one latest-change harvest item, preferring deletion, audit, and `record-backfill` publication signals over historic `record-semantic` rows; explicit `source=` filters still expose source-specific rows for diagnostics and evidence checks. The cursor feed keeps embedded `linkedArt` by default, while IIIF Change Discovery pages are thin by default for immutable-page harvesters. Add `embed=linked-art` to a collection or page URL to include the richer `linkedArt` projection in fixed-page responses. Partners can verify the event handoff by reading `type=Update`, then dereferencing the first row's `linkedArt.id`; the returned `/api/events/...` entity should keep the same id, `_complete: false`, and source-preserving `equivalent[]`.\n\nThe feed includes a conservative `record-backfill` source: if a stored record is not already represented by an audit or deletion activity, MetaMuseum emits one thin `Create` publication activity for that record. Semantic collection events such as production, creation, encounter, or custody transfer remain separate and do not suppress this bootstrap publication row, because external harvesters need a current-record publication signal as well as historic object events. Backfill timestamps prefer record/source update or import metadata such as `_source.importedAt`; for initial production seed rows, these are import/republication times rather than original museum object-change times. Unresolved timestamps still fall back to the epoch marker described below. Activity objects also carry an `equivalent[]` array with cross-dataset `equivalent[]` identifiers derived from stored `equivalent[]`, provider record URLs, provider collection URLs, and provider object Wikidata URLs when available.\n\nWhen an activity `object.id` dereferences through `/api/records/{id}`, the detail response serializes the record `id` as the canonical HTTP(S) detail URL, aligns the embedded record `_links.self.href` with that URL, and exposes the stored/provider identity in `equivalent[]`. This keeps a dereferenceable `object.id` on MetaMuseum Linked Art records while preserving the source record and import identity. Record detail responses also emit HTTP `Link` headers for autodiscovery: `rel=\"http://iiif.io/api/discovery/1#activity\"` points at `/api/activity/collection`, while `rel=\"alternate\"` points at the cursor feed and object-scoped feed.\n\n## Semantic Event Extraction\n\nThe feed extracts semantic events from these stored Linked Art record properties:\n\n| Record property | Linked Art event type | ActivityStreams type |\n|---|---|---|\n| `produced_by` | `Production` | `Create` |\n| `created_by` | `Creation` | `Create` |\n| `attributed_by` | `AttributeAssignment` | `Update` |\n| `modified_by` | `Modification` | `Update` |\n| `destroyed_by` | `Destruction` | `Update` |\n| `removed_by` | `PartRemoval` | `Create` |\n| `encountered_by` | `Encounter` | `Update` |\n| `formed_by` | `Formation` | `Create` |\n| `dissolved_by` | `Dissolution` | `Update` |\n| `born` | `Birth` | `Create` |\n| `died` | `Death` | `Update` |\n| `transferred_title_of` | `TransferOfTitle` | `Update` |\n| `transferred_custody_of` | `TransferOfCustody` | `Update` |\n| `used_for` | `Activity` | `Update` |\n\nSemantic `Destruction`, `Dissolution`, and `Death` describe lifecycle facts inside the Linked Art record, so MetaMuseum publishes them as ActivityStreams `Update` rows. ActivityStreams `Delete` remains reserved for real record/tombstone deletions from the deletion evidence pipeline, especially genuine upstream `404` or `410` cases.\n\nWrite-audit and deletion events still emit a generic Linked Art `Activity` projection so every activity item has a Linked Art-facing payload, even when the source event is operational rather than semantic.\n\n## Synchronization\n\nConsumers may use:\n\n- `limit`: page size, clamped to `1..100`\n- `offset`: backward-compatible page offset\n- `cursor`: stable descending-time cursor from `nextCursor`\n- `type`: `Create`, `Update`, or `Delete`\n- `source`: `audit`, `record-backfill`, `record-semantic`, or `deletion`\n- `provider`: exact provider key such as `met`, `vanda`, or `museumsvictoria`\n- `object` / `objectId`: exact object URI filter\n- `since` / `until`: timestamp range filters\n\nThe default page size is `25` when `limit` is absent, and explicit `limit` values are clamped to `1..100`.\n\nThe canonical `next` link prefers cursor sync only when the page boundary has a valid non-fallback timestamp. If a source event carries an invalid timestamp, `next` falls back to the offset-based `nextPage` link instead of emitting an unusable cursor. The `nextPage` alias remains offset-based for existing consumers.\n\n## IIIF Change Discovery Compatibility\n\nThis profile now includes a first IIIF Change Discovery API 1.0 compatibility layer. `/api/activity/collection` exposes a spec-shaped `OrderedCollection` with mandatory `first` and `last` page references, including the mandatory collection `last` link, and `/api/activity/page/{page}` exposes fixed ascending `OrderedCollectionPage` resources so IIIF/LOUD harvesters can start at `last`, walk `prev`, and stop at their last processed timestamp. Declared consumer IDs sent to the collection and page endpoints are recorded in the same readiness ledger as cursor-feed reads; page reads also merge the concrete activity types observed on that page. The original descending cursor API remains documented as a MetaMuseum extension for tail-following consumers.\n\nExample walk-back seed:\n\n```bash\ncurl \"https://www.metamuseum.org/api/activity/collection?limit=100&provider=met\" \\\n  -H \"accept: application/activity+json\"\n```\n\nEach fixed page lists older activities first and newer activities last, matching the Change Discovery consumption model. Fixed pages omit absent `prev` and `next` links, normalize non-parseable source times to a valid UTC fallback with the original value preserved under `extensions.sourceEndTime`, and keep record-backed `object.id` values dereferenceable by pointing them at `/api/records/{encodedSourceRecordId}`. Epoch fallback timestamps are structurally valid but are not treated as production-quality incremental-sync evidence because they sort as the oldest possible changes; the evidence-grade production consumer run should wait for provider backfill with real event, import, or republication times and populated reconciliation hooks. Filter parameters such as `provider`, `type`, `source`, `object`, `since`, and `until` are preserved across collection, page, and cursor URLs; `embed=linked-art` is preserved across fixed-page traversal when requested.\n\nOpen partner compatibility work:\n\n- Use the passing `metahistorybook-harvester-prod`, `daily-metahistorybook-prod`, and `wikidataexplorer-metamuseum-prod` reads plus their three verified callback rows as production-grade external-consumer evidence, then collect observed `Update`/`Delete` feed-read coverage for the strict syndication gate.\n- Produce `Update` coverage only from a real reviewed record revision, which audits an existing-record POST as `record.update`; produce `Delete` coverage only from `pnpm activity:tombstone:evidence` after a canonical upstream record returns HTTP `404` or `410` with a real evidence reference.\n- Expand cross-dataset `equivalent[]` identifiers beyond the current object-level provider URL and object-Wikidata mapping wherever additional providers expose safe object-level equivalents.\n- Publish an explicit `Refresh` activity if a future full republication needs to mark a new corpus baseline.\n- State delivery, deletion-tombstone retention, and cursor monotonicity guarantees with concrete retention windows.\n- Collect evidence from a real signed callback delivery. Subscription records now declare HMAC-SHA256 signing metadata with `x-metamuseum-signature` and `x-metamuseum-signature-timestamp`, but strict evidence still requires an observed partner callback POST.\n- Publish retry semantics for callback delivery.\n\n## External Evidence Contract\n\nPartner-owned consumers identify themselves with `x-linked-art-consumer-id` when reading `/api/activity`, `/api/activity/collection`, `/api/activity/page/{page}`, or an object-scoped feed. A consumer counts toward strict evidence only after real feed-read telemetry, activity-type coverage, durable subscription evidence, callback verification, and the refreshed syndication-evidence packet are present. Community outreach and placeholder IDs remain context only.\n\nPartner onboarding steps and copy/paste commands live in [activity-stream-partner-quickstart.md](activity-stream-partner-quickstart.md).\n\nVerification:\n\n```powershell\nnode --import tsx --test --test-concurrency=1 tests/api/activity.test.ts tests/api/activity-as2.test.ts\npnpm activity:syndication:evidence\n```\n","sections":[{"level":2,"heading":"Endpoints","anchor":"endpoints"},{"level":2,"heading":"Item Shape","anchor":"item-shape"},{"level":2,"heading":"Semantic Event Extraction","anchor":"semantic-event-extraction"},{"level":2,"heading":"Synchronization","anchor":"synchronization"},{"level":2,"heading":"IIIF Change Discovery Compatibility","anchor":"iiif-change-discovery-compatibility"},{"level":2,"heading":"External Evidence Contract","anchor":"external-evidence-contract"}],"html":"<h1 id=\"metamuseum-linked-art-activity-stream-profile\">MetaMuseum Linked Art Activity Stream Profile</h1>\n<p>Last updated: 2026-07-07</p>\n<p>MetaMuseum exposes `/api/activity` as an ActivityStreams 2.0 change feed with an embedded Linked Art projection on each activity item. The feed is designed for downstream collection-data consumers that need incremental synchronization while preserving Linked Art event semantics.</p>\n<h2 id=\"endpoints\">Endpoints</h2>\n<p>| Endpoint | Purpose |</p>\n<p>|---|---|</p>\n<p>| `/api/activity` | Global ActivityStreams `OrderedCollectionPage` over local write-audit, deletion, and semantic record activities. |</p>\n<p>| `/api/activity/collection` | IIIF Change Discovery-compatible `OrderedCollection` with mandatory `first` and `last` page references. |</p>\n<p>| `/api/activity/page/{page}` | Fixed ascending `OrderedCollectionPage` resources for walk-back harvesters. |</p>\n<p>| `/api/activity/object/{encodedObjectId}` | Object-scoped `OrderedCollectionPage` for one Linked Art object URI. |</p>\n<p>| `/api/activity/readiness` | External-consumer readiness ledger populated by declared feed reads. |</p>\n<p>| `/api/activity/subscriptions` | Durable callback subscription registry and verification target for downstream aggregators. |</p>\n<p>| `/api/providers/capabilities` | Provider and activity-syndication capability document, including discovery rels, endpoint templates, filters, and callback signing headers. |</p>\n<p>All activity endpoints support `GET` and `OPTIONS`, CORS, and `application/activity+json`.</p>\n<h2 id=\"item-shape\">Item Shape</h2>\n<p>Each `/api/activity` cursor-feed `orderedItems[]` entry is an ActivityStreams activity with:</p>\n<ul><li>`type`: `Create`, `Update`, or `Delete`</li><li>`endTime`: valid UTC synchronization timestamp; original invalid source times are retained under `extensions.sourceEndTime`</li><li>`object`: the affected object or tombstone, including dereferenceable `id`, optional `sourceId`, `activityHref`, and optional `equivalent[]` reconciliation links</li><li>`source.kind`: `audit`, `record-backfill`, `record-semantic`, or `deletion`</li><li>`linkedArt`: a Linked Art JSON-LD projection with `@context: https://linked.art/ns/v1/linked-art.json`; embedded `linkedArt.id` values dereference through `/api/events/{encodedSourceActivityId}`, carry `_complete: false`, and preserve source activity identity in `equivalent[]` when available</li></ul>\n<p>For semantic collection events, `linkedArt` preserves event-centric fields such as `type`, `timespan`, `_complete`, names, classifications, object-specific target links (`produced`, `created`, `modified`, `destroyed`, `removed`, `encountered`, `formed`, `dissolved`), `used_specific_object`, and `carried_out_by` when those fields are valid for the activity class. `Set` collection records emit `Creation`/`created` rows, not physical `Production` rows, and record detail responses preserve `member_of` on the member record rather than inventing inverse `member[]` lists on the Set. Provenance wrapper activities also preserve relative `before`/`after` ordering and bundled `part[]` entries such as `Encounter`, `Acquisition`, `RightAcquisition`, `TransferOfCustody`, indeterminate `Transfer`, `Move`, and `Payment`, including nested find/rediscovery, title-transfer, rights-establishment/invalidation, percentage ownership shares, copyright, custody-transfer, unknown-transfer, movement origin/destination, multiple-owner, agent, exchange, loan, theft/loss, and commission/service payment details. Auction activities preserve auction-house/place classifications, auction-of-lot identifiers, lot `Set` `used_specific_object` values, `part_of` links to the overall auction, and provenance purchases `caused_by` the lot auction. Exhibition activities preserve exhibiting classifications, venue and organizer metadata, source descriptions, object-list `Set` links, concept `PropositionalObject` influence, and travelling-exhibition `part_of` links. Conservation coverage keeps condition assessments as `AttributeAssignment` rows with `assigned_property` and `assigned` condition types, separate from conservation `Modification` rows with technique, actor, description, timespan, and shared project `part_of` links. `Birth` and `Death` projections intentionally suppress `carried_out_by` and `used_specific_object`, matching the Linked Art activity-class restrictions.</p>\n<p>Default `/api/activity` cursor-feed responses and IIIF Change Discovery pages use the same partner-facing projection: valid UTC `endTime`, dereferenceable MetaMuseum `object.id` values, optional `object.sourceId` with the stored/provider record id when the projected id differs, `object.activityHref`, `source.kind`, and provider metadata. Default responses collapse duplicate rows for the same projected `object.id` to one latest-change harvest item, preferring deletion, audit, and `record-backfill` publication signals over historic `record-semantic` rows; explicit `source=` filters still expose source-specific rows for diagnostics and evidence checks. The cursor feed keeps embedded `linkedArt` by default, while IIIF Change Discovery pages are thin by default for immutable-page harvesters. Add `embed=linked-art` to a collection or page URL to include the richer `linkedArt` projection in fixed-page responses. Partners can verify the event handoff by reading `type=Update`, then dereferencing the first row&#39;s `linkedArt.id`; the returned `/api/events/...` entity should keep the same id, `_complete: false`, and source-preserving `equivalent[]`.</p>\n<p>The feed includes a conservative `record-backfill` source: if a stored record is not already represented by an audit or deletion activity, MetaMuseum emits one thin `Create` publication activity for that record. Semantic collection events such as production, creation, encounter, or custody transfer remain separate and do not suppress this bootstrap publication row, because external harvesters need a current-record publication signal as well as historic object events. Backfill timestamps prefer record/source update or import metadata such as `_source.importedAt`; for initial production seed rows, these are import/republication times rather than original museum object-change times. Unresolved timestamps still fall back to the epoch marker described below. Activity objects also carry an `equivalent[]` array with cross-dataset `equivalent[]` identifiers derived from stored `equivalent[]`, provider record URLs, provider collection URLs, and provider object Wikidata URLs when available.</p>\n<p>When an activity `object.id` dereferences through `/api/records/{id}`, the detail response serializes the record `id` as the canonical HTTP(S) detail URL, aligns the embedded record `_links.self.href` with that URL, and exposes the stored/provider identity in `equivalent[]`. This keeps a dereferenceable `object.id` on MetaMuseum Linked Art records while preserving the source record and import identity. Record detail responses also emit HTTP `Link` headers for autodiscovery: `rel=&quot;http://iiif.io/api/discovery/1#activity&quot;` points at `/api/activity/collection`, while `rel=&quot;alternate&quot;` points at the cursor feed and object-scoped feed.</p>\n<h2 id=\"semantic-event-extraction\">Semantic Event Extraction</h2>\n<p>The feed extracts semantic events from these stored Linked Art record properties:</p>\n<p>| Record property | Linked Art event type | ActivityStreams type |</p>\n<p>|---|---|---|</p>\n<p>| `produced_by` | `Production` | `Create` |</p>\n<p>| `created_by` | `Creation` | `Create` |</p>\n<p>| `attributed_by` | `AttributeAssignment` | `Update` |</p>\n<p>| `modified_by` | `Modification` | `Update` |</p>\n<p>| `destroyed_by` | `Destruction` | `Update` |</p>\n<p>| `removed_by` | `PartRemoval` | `Create` |</p>\n<p>| `encountered_by` | `Encounter` | `Update` |</p>\n<p>| `formed_by` | `Formation` | `Create` |</p>\n<p>| `dissolved_by` | `Dissolution` | `Update` |</p>\n<p>| `born` | `Birth` | `Create` |</p>\n<p>| `died` | `Death` | `Update` |</p>\n<p>| `transferred_title_of` | `TransferOfTitle` | `Update` |</p>\n<p>| `transferred_custody_of` | `TransferOfCustody` | `Update` |</p>\n<p>| `used_for` | `Activity` | `Update` |</p>\n<p>Semantic `Destruction`, `Dissolution`, and `Death` describe lifecycle facts inside the Linked Art record, so MetaMuseum publishes them as ActivityStreams `Update` rows. ActivityStreams `Delete` remains reserved for real record/tombstone deletions from the deletion evidence pipeline, especially genuine upstream `404` or `410` cases.</p>\n<p>Write-audit and deletion events still emit a generic Linked Art `Activity` projection so every activity item has a Linked Art-facing payload, even when the source event is operational rather than semantic.</p>\n<h2 id=\"synchronization\">Synchronization</h2>\n<p>Consumers may use:</p>\n<ul><li>`limit`: page size, clamped to `1..100`</li><li>`offset`: backward-compatible page offset</li><li>`cursor`: stable descending-time cursor from `nextCursor`</li><li>`type`: `Create`, `Update`, or `Delete`</li><li>`source`: `audit`, `record-backfill`, `record-semantic`, or `deletion`</li><li>`provider`: exact provider key such as `met`, `vanda`, or `museumsvictoria`</li><li>`object` / `objectId`: exact object URI filter</li><li>`since` / `until`: timestamp range filters</li></ul>\n<p>The default page size is `25` when `limit` is absent, and explicit `limit` values are clamped to `1..100`.</p>\n<p>The canonical `next` link prefers cursor sync only when the page boundary has a valid non-fallback timestamp. If a source event carries an invalid timestamp, `next` falls back to the offset-based `nextPage` link instead of emitting an unusable cursor. The `nextPage` alias remains offset-based for existing consumers.</p>\n<h2 id=\"iiif-change-discovery-compatibility\">IIIF Change Discovery Compatibility</h2>\n<p>This profile now includes a first IIIF Change Discovery API 1.0 compatibility layer. `/api/activity/collection` exposes a spec-shaped `OrderedCollection` with mandatory `first` and `last` page references, including the mandatory collection `last` link, and `/api/activity/page/{page}` exposes fixed ascending `OrderedCollectionPage` resources so IIIF/LOUD harvesters can start at `last`, walk `prev`, and stop at their last processed timestamp. Declared consumer IDs sent to the collection and page endpoints are recorded in the same readiness ledger as cursor-feed reads; page reads also merge the concrete activity types observed on that page. The original descending cursor API remains documented as a MetaMuseum extension for tail-following consumers.</p>\n<p>Example walk-back seed:</p>\n<pre><code>\ncurl &quot;https://www.metamuseum.org/api/activity/collection?limit=100&amp;provider=met&quot; \\\n  -H &quot;accept: application/activity+json&quot;\n</code></pre>\n<p>Each fixed page lists older activities first and newer activities last, matching the Change Discovery consumption model. Fixed pages omit absent `prev` and `next` links, normalize non-parseable source times to a valid UTC fallback with the original value preserved under `extensions.sourceEndTime`, and keep record-backed `object.id` values dereferenceable by pointing them at `/api/records/{encodedSourceRecordId}`. Epoch fallback timestamps are structurally valid but are not treated as production-quality incremental-sync evidence because they sort as the oldest possible changes; the evidence-grade production consumer run should wait for provider backfill with real event, import, or republication times and populated reconciliation hooks. Filter parameters such as `provider`, `type`, `source`, `object`, `since`, and `until` are preserved across collection, page, and cursor URLs; `embed=linked-art` is preserved across fixed-page traversal when requested.</p>\n<p>Open partner compatibility work:</p>\n<ul><li>Use the passing `metahistorybook-harvester-prod`, `daily-metahistorybook-prod`, and `wikidataexplorer-metamuseum-prod` reads plus their three verified callback rows as production-grade external-consumer evidence, then collect observed `Update`/`Delete` feed-read coverage for the strict syndication gate.</li><li>Produce `Update` coverage only from a real reviewed record revision, which audits an existing-record POST as `record.update`; produce `Delete` coverage only from `pnpm activity:tombstone:evidence` after a canonical upstream record returns HTTP `404` or `410` with a real evidence reference.</li><li>Expand cross-dataset `equivalent[]` identifiers beyond the current object-level provider URL and object-Wikidata mapping wherever additional providers expose safe object-level equivalents.</li><li>Publish an explicit `Refresh` activity if a future full republication needs to mark a new corpus baseline.</li><li>State delivery, deletion-tombstone retention, and cursor monotonicity guarantees with concrete retention windows.</li><li>Collect evidence from a real signed callback delivery. Subscription records now declare HMAC-SHA256 signing metadata with `x-metamuseum-signature` and `x-metamuseum-signature-timestamp`, but strict evidence still requires an observed partner callback POST.</li><li>Publish retry semantics for callback delivery.</li></ul>\n<h2 id=\"external-evidence-contract\">External Evidence Contract</h2>\n<p>Partner-owned consumers identify themselves with `x-linked-art-consumer-id` when reading `/api/activity`, `/api/activity/collection`, `/api/activity/page/{page}`, or an object-scoped feed. A consumer counts toward strict evidence only after real feed-read telemetry, activity-type coverage, durable subscription evidence, callback verification, and the refreshed syndication-evidence packet are present. Community outreach and placeholder IDs remain context only.</p>\n<p>Partner onboarding steps and copy/paste commands live in activity-stream-partner-quickstart.md(activity-stream-partner-quickstart.md).</p>\n<p>Verification:</p>\n<pre><code>\nnode --import tsx --test --test-concurrency=1 tests/api/activity.test.ts tests/api/activity-as2.test.ts\npnpm activity:syndication:evidence\n</code></pre>","updatedAt":"2018-10-20T01:46:40.000Z","checksum":"adb634532df8a934e551ea1251ba5c3845040e7d11731c64b142640ac33690b6","checksumPrefix":"adb634532df8","anchorCount":6,"lineCount":116,"rawUrl":"/api/docs/content?path=linked-art%2Factivity-stream-profile.md","htmlUrl":"/docs?doc=linked-art%2Factivity-stream-profile.md","apiUrl":"/api/docs/content?path=linked-art%2Factivity-stream-profile.md"}