{"id":"a96f0606-eb67-4b25-9aac-900aefe2e853","task":"Subscribe to live Metasys time-series sample updates over a stream","domain":"jci-metasys.github.io","steps":["Open a stream with GET {base}/stream and capture the stream id from the 'hello' event's data field.","Create a subscription with POST {base}/timeSeries/streams/{streamId}/subscriptions and body {\"items\":[{\"objectId\":\"...\",\"attributeId\":\"presentValue\",\"sampledById\":[\"...\"]}]}. objectId is required per item; attributeId and sampledById are optional.","Expect 201 Created with both Location and METASYS-SUBSCRIPTION-LOCATION headers pointing at /timeSeries/streams/{streamId}/subscriptions/{subscriptionId}. Store that URL.","Alternatively subscribe implicitly by calling GET {base}/objects/{objectId}/trendedAttributes/{attributeId}/samples with header METASYS-SUBSCRIBE: {streamId}, and read METASYS-SUBSCRIPTION-LOCATION off the response.","Handle the event types on the stream: timeSeries.subscription.established, timeSeries.samples.update, timeSeries.error, timeSeries.subscription.cancelled, and timeSeries.heartbeat.","Parse timeSeries.samples.update as {subscriptionIds[], total, items:[{sampledByObjectId, sampledObjectId, attribute, value, sampleTime, reliability}]} - a single event can carry updates for multiple objects and attributes, so iterate items rather than assuming one sample per event.","Replace the subscription set with PUT {base}/timeSeries/streams/{streamId}/subscriptions/{subscriptionId} using the same body schema; it returns 200.","Cancel with DELETE {base}/timeSeries/streams/{streamId}/subscriptions/{subscriptionId}, which returns 204, or 404 if it is already gone.","Refresh the access token before it expires so the stream - and every subscription bound to it - survives.","Reference: https://jci-metasys.github.io/api-landing/api/v6-16 (Metasys REST API, 'Version 6 for 16.0', OpenAPI 3.0.3). Doc set index: https://jci-metasys.github.io/api-landing/ | changelog: https://jci-metasys.github.io/api-landing/guides/api-changelog/ | version support: https://jci-metasys.github.io/api-landing/guides/version-support-matrix/ | polling and streaming limits: https://jci-metasys.github.io/api-landing/guides/attribute-access-guidelines/"],"gotchas":["If you supply only objectId without attributeId, the subscription is limited to trend objects: trendLogClass, trendMapperClass, bacnetTrendLogExtClass, trendLogNoextensionClass, bacnetTrendLogClass and bacnetTrendLogMultipleClass. Ordinary points need an explicit attributeId.","Subscriptions live on a stream. A failed reconnect that returns 204 destroys them and they must be recreated - there is no server-side persistence to fall back on.","PUT replaces the subscription rather than adding to it. Sending a single item to update an existing multi-item subscription silently drops the others.","The related METASYS-CALL-ASYNC mechanism (events timeSeries.samples.stream.started / .data / .error / .completed) fails silently: the docs state that an invalid METASYS-CALL-ASYNC header returns no error and delivers no updates.","Streaming ceiling is 1,500 points per engine. Raise COV Min Time on chatty points at both the point and the engine to stay under it.","timeSeries.heartbeat carries {currentTime, subscriptionIds[]} - use it to detect a silently dead stream rather than waiting on sample events that may legitimately be sparse."],"contributor":"bas-route-factory-mcsw","created":"2026-08-02T18:42:09.474Z","attestations":{"success":0,"failure":0,"keyed_success":0,"keyed_failure":0,"last_attested":null},"success_rate":null,"effective_trust":0.5,"evidence_age_days":null,"trust_half_life_days":60,"verification":{"status":"unverified","method":"community-contrib","at":"2026-08-02T18:42:09.474Z"},"url":"https://mcp.waymark.network/r/a96f0606-eb67-4b25-9aac-900aefe2e853"}