# revokeTrainingCertificate

mutation · in the family [Training](/reference/training/)

## What it does

Withdraw a certificate with a reason — the person passes the course again to be certified anew.

Withdraw a certificate (valid → revoked, terminal) WITH a reason — required (1..256 characters), it rides the revision's cause; the requirement reads unmet until the person passes again. Requires the unrestricted capability + the training-manage right + the CURRENT revision.

## What happens

Permanent for that certificate; the requirement reads as unmet until a new pass.

## Who may call it

Capability area: **Training** — Courses, tests, certificates and the training rules of your team.

- Owner
- System Administrator
- Manager
- An API key whose scope allows `api:revokeTrainingCertificate`

## Arguments

| Name | Type | Required | Notes |
| --- | --- | --- | --- |
| `id` | [ID](/types/#scalars) `ID!` | yes | The id of the record. |
| `revision` | [ID](/types/#scalars) `ID!` | yes | The revision id you read on the record; the change is refused if an edit landed in the meantime. |
| `reason` | [String](/types/#scalars) `String!` | yes | No further notes. |

## Returns

[TrainingCertificate](/types/TrainingCertificate/) `TrainingCertificate!` — 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.

## Example request

```graphql
mutation ExampleRevokeTrainingCertificate($id: ID!, $revision: ID!, $reason: String!) {
  revokeTrainingCertificate(id: $id, revision: $revision, reason: $reason) {
    id
    sysId
    type
    caption
    status
    parentId
    rootId
    createdAt
    updatedAt
    revisionNum
    revision
    userId
    courseKey
    attemptId
    score
    passMark
    issuedAt
    curriculumVersion
    expiresAt
    refreshDue
  }
}
```

Variables:

```json
{
  "id": "01900000-0000-7000-8000-37386ae00000",
  "revision": "01900000-0000-7000-8000-b7960e180000",
  "reason": "Correcting a miscount."
}
```

Send it with the envelope naming the version: `"extensions": {"at": {"version": {"name":"genesis","number":0}}}`.

## Example response

```json
{
  "data": {
    "revokeTrainingCertificate": {
      "id": "01900000-0000-7000-8000-37386ae00000",
      "sysId": "TC-EXMP-0000-000F",
      "type": "TrainingCertificate",
      "caption": "Blue jeans",
      "status": "valid",
      "parentId": "01900000-0000-7000-8000-065235280000",
      "rootId": "01900000-0000-7000-8000-a093dd800000",
      "createdAt": "2027-01-31T00:00:00.000Z",
      "updatedAt": "2027-01-31T00:00:00.000Z",
      "revisionNum": 1,
      "revision": "01900000-0000-7000-8000-b7960e180000",
      "userId": "01900000-0000-7000-8000-11f967df0000",
      "courseKey": "<course key>",
      "attemptId": "01900000-0000-7000-8000-ca1745530000",
      "score": 1,
      "passMark": 1,
      "issuedAt": "2027-01-31T00:00:00.000Z",
      "curriculumVersion": "<curriculum version>",
      "expiresAt": "2027-01-31T00:00:00.000Z",
      "refreshDue": true
    }
  },
  "extensions": {
    "at": {
      "callId": "01EXAMPLE-CALL-ID",
      "version": {
        "requested": {
          "name": "genesis",
          "number": 0
        },
        "serviced": {
          "name": "genesis",
          "number": 0
        }
      }
    }
  }
}
```

## Errors this call can answer

- `VALIDATION/INVALID` — Something in the request is not valid. ([VALIDATION](/errors/VALIDATION/))
- `AUTHN/REQUIRED` — Sign in to do this. ([AUTHN](/errors/AUTHN/))
- `AUTHZ/FORBIDDEN` — Your role does not allow this action. ([AUTHZ](/errors/AUTHZ/))
- `RATE_LIMIT/THROTTLED` — Too many requests in a short time. ([RATE_LIMIT](/errors/RATE_LIMIT/))
- `NOT_FOUND/*` — That record could not be found. ([NOT_FOUND](/errors/NOT_FOUND/))
- `CONFLICT/*` — The record’s state, or a change made in the meantime, does not allow this; the codes are on the CONFLICT page. ([CONFLICT](/errors/CONFLICT/))
- `VALIDATION/VERSION_REQUIRED` — The request did not say which app version it came from. ([VALIDATION](/errors/VALIDATION/))
