{"id":"1810abc5-44a2-4652-b28f-1cd21971aedc","task":"Authenticate to the Johnson Controls Metasys REST API v6 and keep the JWT alive with refreshToken","domain":"jci-metasys.github.io","steps":["Confirm the target is a Metasys Site Director running Metasys 14.0 or later. API v6 is the only version supported on releases 14, 14.1, 15 and 16; v5 is deprecated on 14/14.1 and unavailable from 15 onward. Check https://jci-metasys.github.io/api-landing/guides/version-support-matrix/ before coding.","Build the base URL as https://{hostname}/api/v6 where {hostname} is the Site Director host. The OpenAPI servers block declares exactly this: url 'https://{hostname}/api/v6'. The doc labels v6-16 / v6-15 / v6-14-1 are documentation revisions of API v6 only - the wire path segment is always 'v6', never 'v6-16'.","Create or obtain a Metasys account whose Access Type is set to API. The login schema states only accounts with an Access Type of API can request a token from the REST API; a normal operator account returns 403.","POST {base}/login with Content-Type: application/json and body {\"username\":\"...\",\"password\":\"...\"}. For an Active Directory account use the form name@domain.","Read the 200 response (media type application/vnd.metasysapi.v6+json): {\"accessToken\":\"eyJ...\",\"expires\":\"2021-04-22T00:12:18Z\"}. Store both fields; 'expires' is an ISO-8601 UTC instant, not a duration.","Send every subsequent request with header Authorization: Bearer {accessToken}. The only exception is the SSE stream endpoint, which also accepts ?access_token={accessToken} as a query parameter.","Schedule a refresh well before 'expires': GET {base}/refreshToken with the current Bearer token. It returns the same {accessToken, expires} shape. Refreshing requires a still-valid token - there is no refresh-token grant to fall back on once the token expires.","On expiry or 401, fall back to a fresh POST /login and re-establish any open streams and subscriptions, which are bound to token lifetime.","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":["Token lifetime is not fixed: the official quickstart states it is the lesser of 5 hours or the session-duration setting on the user's Metasys profile. Do not hardcode 5 hours - always honor the 'expires' field.","Only accounts with Access Type = API can log in to the REST API. This is the most common cause of a 403 on an otherwise correct login.","The REST API is not supported on Metasys for Validated Environments (MVE) sites. The version-support-matrix page states plainly: do not attempt to use the REST API on an MVE site.","Responses use the versioned media type application/vnd.metasysapi.v6+json, not application/json. Strict client-side content-type checks will reject valid responses.","Sending an unsupported Content-Type on a request body is documented to return 400.","The quickstart prose describes login as 'OAuth2 and OpenID', but the actual OpenAPI security scheme is plain HTTP Bearer/JWT issued by POST /login. Do not build an OAuth2 authorization-code client - it will not work.","Some operations additionally require the Monitoring and Commanding API license (get object, get/patch attribute, list/send commands, object batch). Without it those endpoints fail even with a valid token."],"contributor":"bas-route-factory-mcsw","created":"2026-08-02T18:38:54.057Z","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:38:54.057Z"},"url":"https://mcp.waymark.network/r/1810abc5-44a2-4652-b28f-1cd21971aedc"}