{
  "openapi": "3.1.0",
  "info": {
    "title": "CLR 2.0 / Open Badges 3.0",
    "description": "The CLR 2.0 API serves Open Badges 3.0 achievement definitions, issued AchievementCredentials, and CLR 2.0 ClrCredential bundles. CLR 2.0 embeds Open Badges 3.0; both Badge Connect and CLR-Connect wire paths live on this module. Standards-native IMS bindings use offset pagination, named list envelopes with bare detail responses, and imsx error bodies. Achievement CRUD is available under /ims/ob/v3p0; issued badges and CLR bundles use the Badge Connect and CLR-Connect credential collection paths.",
    "version": "1.0"
  },
  "tags": [
    {
      "name": "Achievement",
      "description": "A tenant-scoped Open Badges 3.0 / CLR 2.0 Achievement definition (TimeBack `ob_achievements`). One Achievement is reused for every issuance; issued badges reference it by sourcedId. Public shape stays minimal — name, description, type, criteria narrative, image URI, and tags — while preserving the TimeBack natural key for ETL."
    },
    {
      "name": "AchievementCredential",
      "description": "A tenant-scoped Open Badges 3.0 AchievementCredential — one issued badge for one learner (TimeBack `ob_issued_badge`). Carries the roster student FK, the achievement definition FK, earn date, and the raw credential JSON (`data`) so ETL can preserve source identity while the public model stays minimal."
    },
    {
      "name": "ClrCredential",
      "description": "A tenant-scoped CLR 2.0 ClrCredential — a signed transcript-style bundle of achievements for one learner (TimeBack `clr_credentials`). Carries display name, roster student FK, achievement sourcedId list, earn date, and raw credential JSON (`data`) as the ETL landing pad."
    }
  ],
  "paths": {
    "/ims/ob/v3p0/achievements": {
      "get": {
        "operationId": "listAchievements",
        "summary": "List achievements",
        "description": "TimeBack write-extension list of Achievement definitions under the Open Badges 3.0 surface. Offset-paginated with X-Total-Count.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "Achievement"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of items to return on this page (default 100, clamped server-side).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Zero-based index of the first item to return (default 0). Ignored when `cursor` is set.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque keyset cursor from the previous page's X-Next-Cursor header. Prefer over deep `offset` when present.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "achievements"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "achievements": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Achievement"
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Total-Count": {
                "description": "The total number of rows matching the request (across all pages). Always present on offset-mode list responses.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-Next-Cursor": {
                "description": "Opaque keyset cursor for the next page (echo as ?cursor=). Present when more rows exist and the order is key-suffixed.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "404": {
            "description": "Not Found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createAchievement",
        "summary": "Create an achievement",
        "description": "Create an Achievement definition (ETL / admin write extension).\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "Achievement"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAchievementRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Achievement"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "404": {
            "description": "Not Found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          }
        }
      }
    },
    "/ims/ob/v3p0/achievements/{sourcedId}": {
      "get": {
        "operationId": "getAchievement",
        "summary": "Get an achievement",
        "description": "Detail read for one Achievement definition by sourcedId.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "Achievement"
        ],
        "parameters": [
          {
            "name": "sourcedId",
            "in": "path",
            "required": true,
            "description": "The achievement sourcedId.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Achievement"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "404": {
            "description": "Problem (achievement_not_found).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "replaceAchievement",
        "summary": "Replace an achievement",
        "description": "Replace an Achievement definition by sourcedId.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "Achievement"
        ],
        "parameters": [
          {
            "name": "sourcedId",
            "in": "path",
            "required": true,
            "description": "The achievement sourcedId.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAchievementRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Achievement"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "404": {
            "description": "Problem (achievement_not_found).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteAchievement",
        "summary": "Delete an achievement",
        "description": "Delete an Achievement definition. Issued credentials that reference it use restrict semantics on achievementSourcedId.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "Achievement"
        ],
        "parameters": [
          {
            "name": "sourcedId",
            "in": "path",
            "required": true,
            "description": "The achievement sourcedId.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "No Content.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "The achievement was deleted."
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "404": {
            "description": "Problem (achievement_not_found).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          }
        }
      }
    },
    "/ims/ob/v3p0/credentials": {
      "get": {
        "operationId": "listAchievementCredentials",
        "summary": "List achievement credentials",
        "description": "Badge Connect–shaped list of issued AchievementCredentials for the tenant. Offset-paginated with X-Total-Count.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "AchievementCredential"
        ],
        "parameters": [
          {
            "name": "studentSourcedId",
            "in": "query",
            "required": false,
            "description": "Restrict to credentials earned by one OneRoster user.",
            "schema": {
              "type": "string"
            },
            "x-filter": {
              "column": "studentSourcedId",
              "operator": "eq"
            }
          },
          {
            "name": "achievementSourcedId",
            "in": "query",
            "required": false,
            "description": "Restrict to credentials for one Achievement definition.",
            "schema": {
              "type": "string"
            },
            "x-filter": {
              "column": "achievementSourcedId",
              "operator": "eq"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of items to return on this page (default 100, clamped server-side).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Zero-based index of the first item to return (default 0). Ignored when `cursor` is set.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque keyset cursor from the previous page's X-Next-Cursor header. Prefer over deep `offset` when present.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "achievementCredentials"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "achievementCredentials": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AchievementCredential"
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Total-Count": {
                "description": "The total number of rows matching the request (across all pages). Always present on offset-mode list responses.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-Next-Cursor": {
                "description": "Opaque keyset cursor for the next page (echo as ?cursor=). Present when more rows exist and the order is key-suffixed.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "404": {
            "description": "Not Found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createAchievementCredential",
        "summary": "Create an achievement credential",
        "description": "Assert / upload an AchievementCredential (Badge Connect upsert + ETL landing write).\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "AchievementCredential"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAchievementCredentialRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AchievementCredential"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "404": {
            "description": "Not Found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          }
        }
      }
    },
    "/ims/ob/v3p0/credentials/{id}": {
      "get": {
        "operationId": "getAchievementCredential",
        "summary": "Get an achievement credential",
        "description": "Detail read for one issued AchievementCredential.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "AchievementCredential"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The credential id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AchievementCredential"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "404": {
            "description": "Problem (achievement_credential_not_found).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "replaceAchievementCredential",
        "summary": "Replace an achievement credential",
        "description": "Replace an issued AchievementCredential by id.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "AchievementCredential"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The credential id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAchievementCredentialRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AchievementCredential"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "404": {
            "description": "Problem (achievement_credential_not_found).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteAchievementCredential",
        "summary": "Delete an achievement credential",
        "description": "Delete an issued AchievementCredential. Prefer status=tobedeleted for sync consumers when soft-retaining.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "AchievementCredential"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The credential id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "No Content.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "The credential was deleted."
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "404": {
            "description": "Problem (achievement_credential_not_found).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          }
        }
      }
    },
    "/ims/clr/v2p0/credentials": {
      "get": {
        "operationId": "listClrCredentials",
        "summary": "List CLR credentials",
        "description": "CLR-Connect list of ClrCredential bundles for the tenant. Offset-paginated with X-Total-Count.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "ClrCredential"
        ],
        "parameters": [
          {
            "name": "studentSourcedId",
            "in": "query",
            "required": false,
            "description": "Restrict to CLR bundles for one OneRoster user.",
            "schema": {
              "type": "string"
            },
            "x-filter": {
              "column": "studentSourcedId",
              "operator": "eq"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of items to return on this page (default 100, clamped server-side).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Zero-based index of the first item to return (default 0). Ignored when `cursor` is set.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque keyset cursor from the previous page's X-Next-Cursor header. Prefer over deep `offset` when present.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "clrCredentials"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "clrCredentials": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ClrCredential"
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Total-Count": {
                "description": "The total number of rows matching the request (across all pages). Always present on offset-mode list responses.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-Next-Cursor": {
                "description": "Opaque keyset cursor for the next page (echo as ?cursor=). Present when more rows exist and the order is key-suffixed.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "404": {
            "description": "Not Found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createClrCredential",
        "summary": "Create a CLR credential",
        "description": "Upload a ClrCredential bundle (CLR-Connect upsert + ETL landing write).\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "ClrCredential"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateClrCredentialRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClrCredential"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "404": {
            "description": "Not Found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          }
        }
      }
    },
    "/ims/clr/v2p0/credentials/{id}": {
      "get": {
        "operationId": "getClrCredential",
        "summary": "Get a CLR credential",
        "description": "Detail read for one ClrCredential bundle.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "ClrCredential"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The CLR credential id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClrCredential"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "404": {
            "description": "Problem (clr_credential_not_found).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "replaceClrCredential",
        "summary": "Replace a CLR credential",
        "description": "Replace a ClrCredential bundle by id.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "ClrCredential"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The CLR credential id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClrCredentialRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClrCredential"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "404": {
            "description": "Problem (clr_credential_not_found).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteClrCredential",
        "summary": "Delete a CLR credential",
        "description": "Delete a ClrCredential bundle. Prefer status=tobedeleted for sync consumers when soft-retaining.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "ClrCredential"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The CLR credential id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "No Content.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "The CLR credential was deleted."
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "404": {
            "description": "Problem (clr_credential_not_found).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/imsx_StatusInfo"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Achievement": {
        "type": "object",
        "properties": {
          "sourcedId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "description": "Natural business key for this achievement definition (TimeBack `ob_achievements.sourced_id`). Together with tenantId this is the composite-natural primary key."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "tobedeleted"
            ],
            "description": "Sync lifecycle status matching TimeBack `status_type` / OneRoster-style soft delete.",
            "default": "active"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "Display name shown in wallets and catalogues (OB/CLR `name`)."
          },
          "description": {
            "type": "string",
            "minLength": 1,
            "description": "Short description shown in wallets and on achievement pages (OB/CLR `description`)."
          },
          "achievementType": {
            "type": "string",
            "enum": [
              "Achievement",
              "ApprenticeshipCertificate",
              "Assessment",
              "Assignment",
              "AssociateDegree",
              "Award",
              "Badge",
              "BachelorDegree",
              "Certificate",
              "CertificateOfCompletion",
              "Certification",
              "CommunityService",
              "Competency",
              "Course",
              "CoCurricular",
              "Degree",
              "Diploma",
              "DoctoralDegree",
              "Fieldwork",
              "GeneralEducationDevelopment",
              "JourneymanCertificate",
              "LearningProgram",
              "License",
              "Membership",
              "ProfessionalDoctorate",
              "QualityAssuranceCredential",
              "MasterCertificate",
              "MasterDegree",
              "MicroCredential",
              "ResearchDoctorate",
              "SecondarySchoolDiploma"
            ],
            "description": "CLR/OB achievementType vocabulary (TimeBack `achievement_type`). Closed to the TimeBack enum for the first-cut landing pad.",
            "default": "Achievement"
          },
          "criteria": {
            "type": "string",
            "minLength": 1,
            "description": "Narrative of what the learner must do to earn the achievement. Stored as plain text to match TimeBack `ob_achievements.criteria` (full Criteria object expands later)."
          },
          "image": {
            "type": "string",
            "maxLength": 2048,
            "description": "Badge artwork URI (TimeBack `ob_achievements.image`). Empty string means no image."
          },
          "tag": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            },
            "uniqueItems": true,
            "description": "Free-form tags for search and grouping (OB/CLR `tag`)."
          },
          "dateLastModified": {
            "type": "string",
            "format": "date-time",
            "readOnly": true,
            "description": "Server-managed last-update timestamp (RFC 3339). Read-only — never accepted on create or update."
          }
        },
        "required": [
          "sourcedId",
          "status",
          "name",
          "description",
          "criteria",
          "dateLastModified"
        ]
      },
      "AchievementCredential": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "active",
              "tobedeleted"
            ],
            "description": "Sync lifecycle status matching TimeBack `status_type`.",
            "default": "active"
          },
          "creatorId": {
            "type": "string",
            "format": "uuid",
            "description": "Optional opaque creator uuid from TimeBack `ob_issued_badge.creator_id` (not a platform FK in the first cut)."
          },
          "studentSourcedId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "description": "OneRoster user sourcedId of the earner (TimeBack `student_sourced_id`). Optional when the source row has no roster join yet.",
            "x-references": "oneroster:user.sourcedId",
            "x-onDelete": "restrict"
          },
          "achievementSourcedId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "description": "FK to the Achievement definition this credential asserts (TimeBack `achievement_sourced_id`).",
            "x-references": "achievement.sourcedId",
            "x-onDelete": "restrict"
          },
          "dateEarned": {
            "type": "string",
            "format": "date-time",
            "description": "When the learner earned the achievement (TimeBack `date_earned`; aligns with OB issuanceDate for the landing pad)."
          },
          "data": {
            "type": "object",
            "description": "Raw AchievementCredential / OpenBadgeCredential JSON from TimeBack `ob_issued_badge.data`. Preserved verbatim for ETL reconciliation; typed VC fields expand later.",
            "additionalProperties": true
          },
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "Stable credential id (TimeBack `ob_issued_badge.id`). Domain natural key (TimeBack `id`). Wire name remains `id`. Together with tenantId this is the composite-natural primary key. Maps to OB AchievementCredential `id`."
          },
          "dateCreatedAt": {
            "type": "string",
            "format": "date-time",
            "readOnly": true,
            "description": "Server-managed row-creation timestamp (RFC 3339). Read-only — never accepted on create or update."
          },
          "dateLastModified": {
            "type": "string",
            "format": "date-time",
            "readOnly": true,
            "description": "Server-managed last-update timestamp (RFC 3339). Read-only — never accepted on create or update."
          }
        },
        "required": [
          "id",
          "status",
          "achievementSourcedId",
          "dateEarned",
          "data",
          "dateCreatedAt",
          "dateLastModified"
        ]
      },
      "ClrCredential": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "active",
              "tobedeleted"
            ],
            "description": "Sync lifecycle status matching TimeBack `status_type`.",
            "default": "active"
          },
          "creatorId": {
            "type": "string",
            "format": "uuid",
            "description": "Optional opaque creator uuid from TimeBack `clr_credentials.creator_id` (not a platform FK in the first cut)."
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "Display name of the CLR bundle (TimeBack `name`; CLR ClrCredential `name`)."
          },
          "studentSourcedId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "description": "OneRoster user sourcedId of the learner (TimeBack `student_sourced_id`). Optional when the source row has no roster join yet.",
            "x-references": "oneroster:user.sourcedId",
            "x-onDelete": "restrict"
          },
          "achievementSourcedIds": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 256
            },
            "minItems": 0,
            "description": "Achievement sourcedIds bundled in this CLR (TimeBack `achievement_sourced_ids`). Stored as text[]; referential checks against achievement are ETL/hook-owned in the first cut (array FK not emitted)."
          },
          "dateEarned": {
            "type": "string",
            "format": "date-time",
            "description": "When the CLR bundle was earned / issued (TimeBack `date_earned`; aligns with CLR issuanceDate for the landing pad)."
          },
          "data": {
            "type": "object",
            "description": "Raw ClrCredential JSON from TimeBack `clr_credentials.data`. Preserved verbatim for ETL reconciliation; typed VC/ClrSubject fields expand later.",
            "additionalProperties": true
          },
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "Stable CLR credential id (TimeBack `clr_credentials.id`). Domain natural key (TimeBack `id`). Wire name remains `id`. Together with tenantId this is the composite-natural primary key. Maps to CLR ClrCredential `id`."
          },
          "dateCreatedAt": {
            "type": "string",
            "format": "date-time",
            "readOnly": true,
            "description": "Server-managed row-creation timestamp (RFC 3339). Read-only — never accepted on create or update."
          },
          "dateLastModified": {
            "type": "string",
            "format": "date-time",
            "readOnly": true,
            "description": "Server-managed last-update timestamp (RFC 3339). Read-only — never accepted on create or update."
          }
        },
        "required": [
          "id",
          "status",
          "name",
          "achievementSourcedIds",
          "dateEarned",
          "data",
          "dateCreatedAt",
          "dateLastModified"
        ]
      },
      "CreateAchievementRequest": {
        "type": "object",
        "description": "Create-Achievement request body (readOnly/server-managed fields excluded).",
        "required": [
          "sourcedId",
          "status",
          "name",
          "description",
          "criteria"
        ],
        "additionalProperties": false,
        "properties": {
          "sourcedId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "description": "Natural business key for this achievement definition (TimeBack `ob_achievements.sourced_id`). Together with tenantId this is the composite-natural primary key."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "tobedeleted"
            ],
            "description": "Sync lifecycle status matching TimeBack `status_type` / OneRoster-style soft delete.",
            "default": "active"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "Display name shown in wallets and catalogues (OB/CLR `name`)."
          },
          "description": {
            "type": "string",
            "minLength": 1,
            "description": "Short description shown in wallets and on achievement pages (OB/CLR `description`)."
          },
          "achievementType": {
            "type": "string",
            "enum": [
              "Achievement",
              "ApprenticeshipCertificate",
              "Assessment",
              "Assignment",
              "AssociateDegree",
              "Award",
              "Badge",
              "BachelorDegree",
              "Certificate",
              "CertificateOfCompletion",
              "Certification",
              "CommunityService",
              "Competency",
              "Course",
              "CoCurricular",
              "Degree",
              "Diploma",
              "DoctoralDegree",
              "Fieldwork",
              "GeneralEducationDevelopment",
              "JourneymanCertificate",
              "LearningProgram",
              "License",
              "Membership",
              "ProfessionalDoctorate",
              "QualityAssuranceCredential",
              "MasterCertificate",
              "MasterDegree",
              "MicroCredential",
              "ResearchDoctorate",
              "SecondarySchoolDiploma"
            ],
            "description": "CLR/OB achievementType vocabulary (TimeBack `achievement_type`). Closed to the TimeBack enum for the first-cut landing pad.",
            "default": "Achievement"
          },
          "criteria": {
            "type": "string",
            "minLength": 1,
            "description": "Narrative of what the learner must do to earn the achievement. Stored as plain text to match TimeBack `ob_achievements.criteria` (full Criteria object expands later)."
          },
          "image": {
            "type": "string",
            "maxLength": 2048,
            "description": "Badge artwork URI (TimeBack `ob_achievements.image`). Empty string means no image."
          },
          "tag": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            },
            "uniqueItems": true,
            "description": "Free-form tags for search and grouping (OB/CLR `tag`)."
          }
        }
      },
      "UpdateAchievementRequest": {
        "type": "object",
        "description": "Update-Achievement request body (partial — all fields optional; readOnly + immutable fields excluded; null clears a nullable column).",
        "additionalProperties": false,
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "active",
              "tobedeleted"
            ],
            "description": "Sync lifecycle status matching TimeBack `status_type` / OneRoster-style soft delete.",
            "default": "active"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "Display name shown in wallets and catalogues (OB/CLR `name`)."
          },
          "description": {
            "type": "string",
            "minLength": 1,
            "description": "Short description shown in wallets and on achievement pages (OB/CLR `description`)."
          },
          "achievementType": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "Achievement",
              "ApprenticeshipCertificate",
              "Assessment",
              "Assignment",
              "AssociateDegree",
              "Award",
              "Badge",
              "BachelorDegree",
              "Certificate",
              "CertificateOfCompletion",
              "Certification",
              "CommunityService",
              "Competency",
              "Course",
              "CoCurricular",
              "Degree",
              "Diploma",
              "DoctoralDegree",
              "Fieldwork",
              "GeneralEducationDevelopment",
              "JourneymanCertificate",
              "LearningProgram",
              "License",
              "Membership",
              "ProfessionalDoctorate",
              "QualityAssuranceCredential",
              "MasterCertificate",
              "MasterDegree",
              "MicroCredential",
              "ResearchDoctorate",
              "SecondarySchoolDiploma",
              null
            ],
            "description": "CLR/OB achievementType vocabulary (TimeBack `achievement_type`). Closed to the TimeBack enum for the first-cut landing pad.",
            "default": "Achievement"
          },
          "criteria": {
            "type": "string",
            "minLength": 1,
            "description": "Narrative of what the learner must do to earn the achievement. Stored as plain text to match TimeBack `ob_achievements.criteria` (full Criteria object expands later)."
          },
          "image": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 2048,
            "description": "Badge artwork URI (TimeBack `ob_achievements.image`). Empty string means no image."
          },
          "tag": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            },
            "uniqueItems": true,
            "description": "Free-form tags for search and grouping (OB/CLR `tag`)."
          }
        }
      },
      "CreateAchievementCredentialRequest": {
        "type": "object",
        "description": "Create-AchievementCredential request body (readOnly/server-managed fields excluded).",
        "required": [
          "id",
          "status",
          "achievementSourcedId",
          "dateEarned",
          "data"
        ],
        "additionalProperties": false,
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "active",
              "tobedeleted"
            ],
            "description": "Sync lifecycle status matching TimeBack `status_type`.",
            "default": "active"
          },
          "creatorId": {
            "type": "string",
            "format": "uuid",
            "description": "Optional opaque creator uuid from TimeBack `ob_issued_badge.creator_id` (not a platform FK in the first cut)."
          },
          "studentSourcedId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "description": "OneRoster user sourcedId of the earner (TimeBack `student_sourced_id`). Optional when the source row has no roster join yet.",
            "x-references": "oneroster:user.sourcedId",
            "x-onDelete": "restrict"
          },
          "achievementSourcedId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "description": "FK to the Achievement definition this credential asserts (TimeBack `achievement_sourced_id`).",
            "x-references": "achievement.sourcedId",
            "x-onDelete": "restrict"
          },
          "dateEarned": {
            "type": "string",
            "format": "date-time",
            "description": "When the learner earned the achievement (TimeBack `date_earned`; aligns with OB issuanceDate for the landing pad)."
          },
          "data": {
            "type": "object",
            "description": "Raw AchievementCredential / OpenBadgeCredential JSON from TimeBack `ob_issued_badge.data`. Preserved verbatim for ETL reconciliation; typed VC fields expand later.",
            "additionalProperties": true
          },
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "Stable credential id (TimeBack `ob_issued_badge.id`). Domain natural key (TimeBack `id`). Wire name remains `id`. Together with tenantId this is the composite-natural primary key. Maps to OB AchievementCredential `id`."
          }
        }
      },
      "UpdateAchievementCredentialRequest": {
        "type": "object",
        "description": "Update-AchievementCredential request body (partial — all fields optional; readOnly + immutable fields excluded; null clears a nullable column).",
        "additionalProperties": false,
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "active",
              "tobedeleted"
            ],
            "description": "Sync lifecycle status matching TimeBack `status_type`.",
            "default": "active"
          },
          "creatorId": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Optional opaque creator uuid from TimeBack `ob_issued_badge.creator_id` (not a platform FK in the first cut)."
          },
          "studentSourcedId": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 1,
            "maxLength": 256,
            "description": "OneRoster user sourcedId of the earner (TimeBack `student_sourced_id`). Optional when the source row has no roster join yet.",
            "x-references": "oneroster:user.sourcedId",
            "x-onDelete": "restrict"
          },
          "dateEarned": {
            "type": "string",
            "format": "date-time",
            "description": "When the learner earned the achievement (TimeBack `date_earned`; aligns with OB issuanceDate for the landing pad)."
          },
          "data": {
            "type": "object",
            "description": "Raw AchievementCredential / OpenBadgeCredential JSON from TimeBack `ob_issued_badge.data`. Preserved verbatim for ETL reconciliation; typed VC fields expand later.",
            "additionalProperties": true
          }
        }
      },
      "CreateClrCredentialRequest": {
        "type": "object",
        "description": "Create-ClrCredential request body (readOnly/server-managed fields excluded).",
        "required": [
          "id",
          "status",
          "name",
          "achievementSourcedIds",
          "dateEarned",
          "data"
        ],
        "additionalProperties": false,
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "active",
              "tobedeleted"
            ],
            "description": "Sync lifecycle status matching TimeBack `status_type`.",
            "default": "active"
          },
          "creatorId": {
            "type": "string",
            "format": "uuid",
            "description": "Optional opaque creator uuid from TimeBack `clr_credentials.creator_id` (not a platform FK in the first cut)."
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "Display name of the CLR bundle (TimeBack `name`; CLR ClrCredential `name`)."
          },
          "studentSourcedId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "description": "OneRoster user sourcedId of the learner (TimeBack `student_sourced_id`). Optional when the source row has no roster join yet.",
            "x-references": "oneroster:user.sourcedId",
            "x-onDelete": "restrict"
          },
          "achievementSourcedIds": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 256
            },
            "minItems": 0,
            "description": "Achievement sourcedIds bundled in this CLR (TimeBack `achievement_sourced_ids`). Stored as text[]; referential checks against achievement are ETL/hook-owned in the first cut (array FK not emitted)."
          },
          "dateEarned": {
            "type": "string",
            "format": "date-time",
            "description": "When the CLR bundle was earned / issued (TimeBack `date_earned`; aligns with CLR issuanceDate for the landing pad)."
          },
          "data": {
            "type": "object",
            "description": "Raw ClrCredential JSON from TimeBack `clr_credentials.data`. Preserved verbatim for ETL reconciliation; typed VC/ClrSubject fields expand later.",
            "additionalProperties": true
          },
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "Stable CLR credential id (TimeBack `clr_credentials.id`). Domain natural key (TimeBack `id`). Wire name remains `id`. Together with tenantId this is the composite-natural primary key. Maps to CLR ClrCredential `id`."
          }
        }
      },
      "UpdateClrCredentialRequest": {
        "type": "object",
        "description": "Update-ClrCredential request body (partial — all fields optional; readOnly + immutable fields excluded; null clears a nullable column).",
        "additionalProperties": false,
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "active",
              "tobedeleted"
            ],
            "description": "Sync lifecycle status matching TimeBack `status_type`.",
            "default": "active"
          },
          "creatorId": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Optional opaque creator uuid from TimeBack `clr_credentials.creator_id` (not a platform FK in the first cut)."
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "Display name of the CLR bundle (TimeBack `name`; CLR ClrCredential `name`)."
          },
          "studentSourcedId": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 1,
            "maxLength": 256,
            "description": "OneRoster user sourcedId of the learner (TimeBack `student_sourced_id`). Optional when the source row has no roster join yet.",
            "x-references": "oneroster:user.sourcedId",
            "x-onDelete": "restrict"
          },
          "achievementSourcedIds": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 256
            },
            "minItems": 0,
            "description": "Achievement sourcedIds bundled in this CLR (TimeBack `achievement_sourced_ids`). Stored as text[]; referential checks against achievement are ETL/hook-owned in the first cut (array FK not emitted)."
          },
          "dateEarned": {
            "type": "string",
            "format": "date-time",
            "description": "When the CLR bundle was earned / issued (TimeBack `date_earned`; aligns with CLR issuanceDate for the landing pad)."
          },
          "data": {
            "type": "object",
            "description": "Raw ClrCredential JSON from TimeBack `clr_credentials.data`. Preserved verbatim for ETL reconciliation; typed VC/ClrSubject fields expand later.",
            "additionalProperties": true
          }
        }
      },
      "imsx_StatusInfo": {
        "type": "object",
        "description": "1EdTech imsx_StatusInfo — the status/error payload mandated on every non-2xx response.",
        "required": [
          "imsx_codeMajor",
          "imsx_severity"
        ],
        "properties": {
          "imsx_codeMajor": {
            "type": "string",
            "enum": [
              "success",
              "processing",
              "failure",
              "unsupported"
            ],
            "description": "The major status code."
          },
          "imsx_severity": {
            "type": "string",
            "enum": [
              "status",
              "warning",
              "error"
            ],
            "description": "The severity of the status."
          },
          "imsx_description": {
            "type": "string",
            "description": "A human-readable description of the status."
          },
          "imsx_codeMinor": {
            "type": "object",
            "description": "The minor status codes qualifying the major code.",
            "required": [
              "imsx_codeMinorField"
            ],
            "properties": {
              "imsx_codeMinorField": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "imsx_codeMinorFieldName",
                    "imsx_codeMinorFieldValue"
                  ],
                  "properties": {
                    "imsx_codeMinorFieldName": {
                      "type": "string",
                      "description": "The system the code applies to."
                    },
                    "imsx_codeMinorFieldValue": {
                      "type": "string",
                      "description": "The minor status code value."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    }
  },
  "servers": [
    {
      "url": "https://clr.platform4.alphaschool.dev"
    }
  ]
}
