# TrainingCertificate

object type

A TrainingCertificate (🎓 — THE TRAINING PROGRAM, THE WIRE): the platform's own record that a person passed a course — MINTED BY THE API at a passing submit, in the SAME transaction as the attempt's transition, NEVER by a client (no create op exists on the wire). The holder (userId), the course, the passing sitting (attemptId), the score and the pass mark, the issue instant and the course's content version (curriculumVersion). valid (live) → revoked (terminal; manage authority, a reason required) · valid → superseded (terminal; SYSTEM-ONLY — the person's next pass of the same course supersedes it and keeps it as history). expiresAt is null — 's refresh rule sets it. The by-id read answers the holder or the training-manage right; the listing is the manage right's (revoked drops from it, superseded stays as history; both stay point-readable). NOT searchable.

## Fields

| Field | Type | Notes |
| --- | --- | --- |
| `id` | [ID](/types/#scalars) `ID!` | The record’s id — a UUID the platform assigned when the record was created; every reference to this record uses it. |
| `sysId` | [String](/types/#scalars) `String!` | The group-scoped human-facing system id (TC-…). |
| `type` | [String](/types/#scalars) `String!` | The kind of record — always `TrainingCertificate` here. |
| `caption` | [String](/types/#scalars) `String!` | The record’s display name — what people see it called. |
| `status` | [String](/types/#scalars) `String!` | The FSM state: valid \| superseded \| revoked. |
| `parentId` | [ID](/types/#scalars) `ID!` | The parent org group; for a TrainingCertificate parentId === rootId. |
| `rootId` | [ID](/types/#scalars) `ID!` | The org-group family root. |
| `createdAt` | [String](/types/#scalars) `String!` | When the record was created, as a UTC timestamp. |
| `updatedAt` | [String](/types/#scalars) `String!` | When the record last changed, as a UTC timestamp. |
| `revisionNum` | [Int](/types/#scalars) `Int!` | How many times this record has been edited; the first save is 0. |
| `revision` | [ID](/types/#scalars) `ID!` | The OCC revision token — supply it on every mutation of this record; rotates on every write. |
| `refCaptions` | [RefCaption](/types/RefCaption/) `[RefCaption!]!` | The server-composed captions of this record's declared references (the referenced-caption rule) — one row per referenced id; see RefCaption. |
| `userId` | [ID](/types/#scalars) `ID!` | The holder. IMMUTABLE. |
| `courseKey` | [String](/types/#scalars) `String!` | The course — a live play key. IMMUTABLE. |
| `attemptId` | [ID](/types/#scalars) `ID!` | The passing sitting. IMMUTABLE. |
| `score` | [Int](/types/#scalars) | The sitting’s grade 0..100 — stored on every certificate; NULL on the wire to a NON-subject reader when training.score_visibility is 0 (🎓; the holder always reads it. |
| `passMark` | [Int](/types/#scalars) `Int!` | The pass mark the sitting had to reach. |
| `issuedAt` | [String](/types/#scalars) `String!` | The issue instant (UTC ISO-8601) — the mint transaction’s clock. |
| `curriculumVersion` | [String](/types/#scalars) `String!` | The play’s content hash the course was passed on (16 hex) — ’s refresh rule compares it to today’s. |
| `expiresAt` | [String](/types/#scalars) | null — the refresh rule is CONTENT-based (refreshDue), never time-based (🎓 (b)). |
| `refreshDue` | [Boolean](/types/#scalars) `Boolean!` | DERIVED AT READ TIME, never stored (the twin rule — 🎓): true when the course’s CURRENT content hash differs from curriculumVersion (or the play is gone) — sit again to refresh; the api compares through the kit’s course facts. |

## Used by

- [revokeTrainingCertificate](/reference/training/revokeTrainingCertificate/)
- [trainingCertificate](/reference/training-certificate/trainingCertificate/)
