The XC Log data contract

XC Log v1, maintained by XC Athletes, is /v1/: a versioned, stack-neutral HTTP+JSON API over athlete training data, covering reads, writes, a change feed, and the identity and grant surface a team needs to hold a roster. Any system, not just this one, can adopt it as a training log standard. Athletes own their own record. A team that originates a session or check-in keeps read and export access to what it wrote. That access survives the end of a grant and lasts as long as the platform holds the data.

Tiers

A tier is earned by passing the published black-box conformance suite for it (xclog-conformance), not by holding a token at that tier. The three tiers are named reader (1), writer (2), and roster-aware (3); each is a strict superset of the one before it.

TierAddsConformance covers
1 · readerGET /v1/token, people, training-sessions, checkins, rollups, changesReads, following every replaced_by link and tombstone type in the change feed. Bulk export is not implemented; GET /v1/capabilities reports features.export as false (EXP-01..04)
2 · writerTier 1, plus POST/PATCH/DELETE on training-sessions and checkins, and the by-ref upsertWR-01..09: idempotency keys, If-Match, by-ref upsert, block replacement
3 · roster-awarePOST /v1/people, join-codes/redeem, dob-assertion, person-links, grantsID-01, ID-02, GR-01..02: create with attestation, join-code redemption, grant lifecycle

A conformant integration may state that it passes the xclog-conformance suite at a given tier, for example "passes the xclog-conformance suite, writer tier," and use the matching brand set. The claim is earned by passing the conformance suite for that tier.

Versioning

Within /v1/ the platform only adds optional fields and enum values; it never removes or repurposes one (PRIN-02). A conforming consumer already tolerates this by design (PRIN-03): ignore unknown fields, map an unrecognized modality code to other, and map any other unrecognized enum value to the fallback its own schema description names. A breaking change never lands inside /v1/; it ships as a separate /v2/ beside it, announced with an RFC 9745 Deprecation header and an RFC 8594 Sunset header, and /v1/ keeps running for at least 12 months of overlap after that.

Staying in sync

Poll GET /v1/changes?cursor= every 5 minutes. That is the conformant sync mechanism (SYNC-01). The ?updated_since= filters are a convenience only (SYNC-06). The mirror-sync how-to walks the loop end to end.

Artifacts

Start here

A token comes from your team's operator, who signs in and creates one at /team/tokens. The three how-to guides above (mirror-sync, revoked-token, shared-log) are the spec for writing your own sync loop against it.