{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"version":{"type":"number","const":1,"description":"Contract version. Additive changes do not bump it."},"generated_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"ISO 8601 UTC timestamp of the moment this payload was built."},"roster":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Stable public id of the roster."},"name":{"type":"string","description":"The team's name."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Stable machine key for the field. It never changes once published."},"label":{"type":"string","description":"Human label to render as the field's display name."}},"required":["key","label"],"additionalProperties":true},"description":"The roster's custom field definitions - the key set that `members[].fields` draws from."}},"required":["id","name","fields"],"additionalProperties":true,"description":"The team itself, as distinct from the people on it."},"members":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Stable public id for this teammate. Never reused, even after they're removed."},"display_name":{"type":"string","description":"The teammate's name, exactly as it should appear on your page."},"photo_url":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}],"description":"Absolute CDN URL of the live headshot, or null when this teammate hasn't picked one yet (render your own placeholder avatar). The URL changes whenever the selection changes, so it is safe to cache forever - key your cache on the URL itself. Every headshot in a roster is cut to the same shape, so a grid of them lines up."},"sort_order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Display order. Members already arrive sorted by this; it's carried for consumers that re-merge."},"fields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"},"description":"Values for the roster's custom fields, keyed by field key. Always strings."}},"required":["id","display_name","photo_url","sort_order","fields"],"additionalProperties":true},"description":"The team, already in display order. Hidden members are omitted entirely."}},"required":["version","generated_at","roster","members"],"additionalProperties":true,"description":"A RosterShots team roster: the team, its custom field definitions, and its members in display order."}