{
  "openapi": "3.1.0",
  "info": {
    "title": "Best Grading Tools API",
    "version": "1.2.0-beta",
    "description": "Card cutouts, custom PDFs and wallet-backed BGT grading. Grading requires explicit live permissions and shares the project owner’s app wallet. No market feed.",
    "termsOfService": "https://bestgradingtools.com/api/terms/"
  },
  "servers": [
    {
      "url": "https://europe-west1-bestgradingtools-prod.cloudfunctions.net/developerApi"
    }
  ],
  "paths": {
    "/v1/health": {
      "get": {
        "summary": "API status",
        "security": [],
        "responses": {
          "200": {
            "description": "API version and processing limits."
          }
        }
      }
    },
    "/v1/cutouts": {
      "post": {
        "security": [
          {
            "BearerKey": []
          }
        ],
        "summary": "Create a transparent card cutout",
        "description": "Requires cutouts:write. Successful output consumes one operation. Test outputs are watermarked.",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{16,128}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "imageBase64": {
                    "type": "string",
                    "minLength": 32,
                    "maxLength": 8000000
                  },
                  "bounds": {
                    "anyOf": [
                      {
                        "type": "object",
                        "properties": {
                          "x": {
                            "type": "number",
                            "minimum": 0,
                            "maximum": 1
                          },
                          "y": {
                            "type": "number",
                            "minimum": 0,
                            "maximum": 1
                          },
                          "width": {
                            "type": "number",
                            "exclusiveMinimum": 0,
                            "maximum": 1
                          },
                          "height": {
                            "type": "number",
                            "exclusiveMinimum": 0,
                            "maximum": 1
                          }
                        },
                        "required": ["x", "y", "width", "height"],
                        "additionalProperties": false
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "width": {
                    "type": "integer",
                    "minimum": 64,
                    "maximum": 1600,
                    "default": 960
                  },
                  "height": {
                    "type": "integer",
                    "minimum": 64,
                    "maximum": 1600,
                    "default": 1344
                  }
                },
                "required": ["imageBase64"],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Private result. Download within 24 hours.",
            "headers": {
              "X-BGT-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-BGT-Environment": {
                "schema": {
                  "type": "string",
                  "enum": ["test", "live"]
                }
              }
            },
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/pdfs": {
      "post": {
        "security": [
          {
            "BearerKey": []
          }
        ],
        "summary": "Create a custom card PDF",
        "description": "Requires pdfs:write. Successful output consumes one operation. Test outputs are watermarked.",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{16,128}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "maxLength": 100
                  },
                  "brand": {
                    "type": "string",
                    "maxLength": 100,
                    "default": ""
                  },
                  "accent": {
                    "type": "string",
                    "pattern": "^#[0-9a-fA-F]{6}$",
                    "default": "#183E63"
                  },
                  "locale": {
                    "type": "string",
                    "enum": ["en", "es", "de"],
                    "default": "en"
                  },
                  "notes": {
                    "type": "string",
                    "maxLength": 1200,
                    "default": ""
                  },
                  "cards": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string",
                          "maxLength": 180
                        },
                        "details": {
                          "type": "string",
                          "maxLength": 300,
                          "default": ""
                        },
                        "score": {
                          "anyOf": [
                            {
                              "type": "number",
                              "minimum": 0,
                              "maximum": 10
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "default": null
                        },
                        "frontImageBase64": {
                          "type": "string",
                          "minLength": 32,
                          "maxLength": 8000000
                        },
                        "backImageBase64": {
                          "type": "string",
                          "minLength": 32,
                          "maxLength": 8000000
                        }
                      },
                      "required": ["name"],
                      "additionalProperties": false
                    },
                    "minItems": 1,
                    "maxItems": 12
                  }
                },
                "required": ["title", "cards"],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Private result. Download within 24 hours.",
            "headers": {
              "X-BGT-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-BGT-Environment": {
                "schema": {
                  "type": "string",
                  "enum": ["test", "live"]
                }
              }
            },
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/gradings/contract": {
      "get": {
        "security": [],
        "summary": "Current grading capture contract and one-token cost",
        "responses": {
          "200": {
            "description": "Product and capture versions, image limits and token cost."
          }
        }
      }
    },
    "/v1/wallet": {
      "get": {
        "security": [
          {
            "BearerKey": []
          }
        ],
        "summary": "Read the owner’s existing token balance; live wallet:read required",
        "responses": {
          "200": {
            "description": "available, reserved, gradingTokenCost: 1 and currency: BGT_TOKEN"
          },
          "400": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/gradings/photos": {
      "post": {
        "security": [
          {
            "BearerKey": []
          }
        ],
        "summary": "Prepare an original front or back photo; live gradings:write required",
        "description": "Upload one opaque JPEG/PNG/WebP up to 4 MB / 12 MP. Use the same clientRequestId and a revision for each side. Optional normalized bounds describe the upright card. No token is reserved at this step. Does not synthesize a flash capture.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "clientRequestId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "side": {
                    "type": "string",
                    "enum": ["front", "back"]
                  },
                  "revision": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000
                  },
                  "imageBase64": {
                    "type": "string",
                    "minLength": 32,
                    "maxLength": 6000000
                  },
                  "bounds": {
                    "type": "object",
                    "properties": {
                      "x": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1
                      },
                      "y": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1
                      },
                      "width": {
                        "type": "number",
                        "exclusiveMinimum": 0,
                        "maximum": 1
                      },
                      "height": {
                        "type": "number",
                        "exclusiveMinimum": 0,
                        "maximum": 1
                      }
                    },
                    "required": ["x", "y", "width", "height"],
                    "additionalProperties": false
                  }
                },
                "required": ["clientRequestId", "side", "revision", "imageBase64"],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Uploaded phase and revision; private storage paths are not returned."
          },
          "400": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/gradings/captures": {
      "post": {
        "security": [
          {
            "BearerKey": []
          }
        ],
        "summary": "Upload one immutable private capture; live gradings:write required",
        "description": "Use the same clientRequestId for every capture and grading. JPEG bytes must match checksum and dimensions. No token is reserved until POST /v1/gradings. Metadata is the same capture contract as the app; metrics are caller-reported and subject to server review.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "capture": {
                    "type": "object",
                    "properties": {
                      "schemaVersion": {
                        "type": "string",
                        "const": "1.0.0"
                      },
                      "clientRequestId": {
                        "type": "string",
                        "format": "uuid"
                      },
                      "productId": {
                        "type": "string",
                        "const": "pokemon-card-grading"
                      },
                      "captureManifestVersion": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 80
                      },
                      "revision": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 10000
                      },
                      "frame": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 120
                          },
                          "phaseId": {
                            "type": "string",
                            "enum": ["front_ambient", "front_torch", "back_ambient", "back_torch"]
                          },
                          "side": {
                            "type": "string",
                            "enum": ["front", "back"]
                          },
                          "illumination": {
                            "type": "string",
                            "enum": ["ambient", "torch"]
                          },
                          "localUri": {
                            "anyOf": [
                              {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 1024
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "storagePath": {
                            "anyOf": [
                              {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 1024
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "checksumSha256": {
                            "type": "string",
                            "pattern": "^[a-f0-9]{64}$"
                          },
                          "width": {
                            "type": "integer",
                            "exclusiveMinimum": 0,
                            "maximum": 4096
                          },
                          "height": {
                            "type": "integer",
                            "exclusiveMinimum": 0,
                            "maximum": 4096
                          },
                          "cardBounds": {
                            "type": "object",
                            "properties": {
                              "x": {
                                "type": "number",
                                "minimum": 0,
                                "maximum": 1
                              },
                              "y": {
                                "type": "number",
                                "minimum": 0,
                                "maximum": 1
                              },
                              "width": {
                                "type": "number",
                                "exclusiveMinimum": 0,
                                "maximum": 1
                              },
                              "height": {
                                "type": "number",
                                "exclusiveMinimum": 0,
                                "maximum": 1
                              }
                            },
                            "required": ["x", "y", "width", "height"],
                            "additionalProperties": false
                          },
                          "captureSource": {
                            "type": "string",
                            "enum": ["video", "photo"]
                          },
                          "sourceResolution": {
                            "type": "object",
                            "properties": {
                              "width": {
                                "type": "integer",
                                "exclusiveMinimum": 0,
                                "maximum": 8192
                              },
                              "height": {
                                "type": "integer",
                                "exclusiveMinimum": 0,
                                "maximum": 8192
                              },
                              "cardLongEdgePixels": {
                                "type": "number",
                                "exclusiveMinimum": 0,
                                "maximum": 8192
                              }
                            },
                            "required": ["width", "height", "cardLongEdgePixels"],
                            "additionalProperties": false
                          },
                          "metrics": {
                            "type": "object",
                            "properties": {
                              "sharpness": {
                                "type": "number",
                                "minimum": 0,
                                "maximum": 1
                              },
                              "detailSharpness": {
                                "type": "number",
                                "minimum": 0,
                                "maximum": 1
                              },
                              "exposure": {
                                "type": "number",
                                "minimum": 0,
                                "maximum": 1
                              },
                              "clipping": {
                                "type": "number",
                                "minimum": 0,
                                "maximum": 1
                              },
                              "glare": {
                                "type": "number",
                                "minimum": 0,
                                "maximum": 1
                              },
                              "motion": {
                                "type": "number",
                                "minimum": 0,
                                "maximum": 1
                              },
                              "coverage": {
                                "type": "number",
                                "minimum": 0,
                                "maximum": 1
                              },
                              "rectangleConfidence": {
                                "type": "number",
                                "minimum": 0,
                                "maximum": 1
                              },
                              "perspectivePenalty": {
                                "type": "number",
                                "minimum": 0,
                                "maximum": 1
                              }
                            },
                            "required": [
                              "sharpness",
                              "exposure",
                              "clipping",
                              "glare",
                              "motion",
                              "coverage",
                              "rectangleConfidence",
                              "perspectivePenalty"
                            ],
                            "additionalProperties": false
                          }
                        },
                        "required": [
                          "id",
                          "phaseId",
                          "side",
                          "illumination",
                          "localUri",
                          "storagePath",
                          "checksumSha256",
                          "width",
                          "height",
                          "cardBounds",
                          "metrics"
                        ],
                        "additionalProperties": false
                      }
                    },
                    "required": [
                      "schemaVersion",
                      "clientRequestId",
                      "productId",
                      "captureManifestVersion",
                      "revision",
                      "frame"
                    ],
                    "additionalProperties": false
                  },
                  "imageBase64": {
                    "type": "string",
                    "minLength": 32,
                    "maxLength": 8000000
                  }
                },
                "required": ["capture", "imageBase64"],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Captured phase and revision; no private storage path."
          },
          "400": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/gradings": {
      "post": {
        "security": [
          {
            "BearerKey": []
          }
        ],
        "summary": "Reserve one wallet token and submit an evaluation",
        "description": "Requires live gradings:write. Uses the same grading engine, wallet and settlement as the app. No cutout/PDF subscription needed. Failures and recaptures refund the reservation. Exact retries never reserve a second token. Use gradings:read to poll.",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "description": "Must equal clientRequestId (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "schemaVersion": {
                    "type": "string",
                    "const": "1.0.0"
                  },
                  "clientRequestId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "productId": {
                    "type": "string",
                    "const": "pokemon-card-grading"
                  },
                  "productVersion": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 40
                  },
                  "captureManifestVersion": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 40
                  },
                  "collectionGroupId": {
                    "anyOf": [
                      {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 128,
                        "pattern": "^[^/]+$"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "sourceLocalCardId": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uuid"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "captureUploadRevisions": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "integer",
                      "minimum": 1,
                      "maximum": 10000
                    },
                    "propertyNames": {
                      "enum": ["front_ambient", "front_torch", "back_ambient", "back_torch"]
                    }
                  },
                  "locale": {
                    "type": "string",
                    "enum": ["de", "es", "en"]
                  }
                },
                "required": [
                  "schemaVersion",
                  "clientRequestId",
                  "productId",
                  "productVersion",
                  "captureManifestVersion",
                  "captureUploadRevisions",
                  "locale"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "id, statusUrl and tokenCost: 1. Poll the status URL."
          },
          "400": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/gradings/{id}": {
      "get": {
        "security": [
          {
            "BearerKey": []
          }
        ],
        "summary": "Read a grading from this project; live gradings:read required",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-f0-9]{48}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "State, progress, tokenState, dates and completed BGT estimate without private storage paths."
          },
          "400": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown or another project’s grading."
          },
          "409": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/usage": {
      "get": {
        "security": [
          {
            "BearerKey": []
          }
        ],
        "summary": "Current UTC month usage; requires usage:read",
        "responses": {
          "200": {
            "description": "Environment, plan, limits and usage counters."
          },
          "400": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/requests/{requestId}": {
      "get": {
        "security": [
          {
            "BearerKey": []
          }
        ],
        "summary": "Retrieve a result from the same project and environment",
        "parameters": [
          {
            "in": "path",
            "name": "requestId",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-f0-9]{64}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Saved PNG or PDF; original operation permission required.",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "API error. See code and message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "bgt_test_… or bgt_live_…. Keep keys on your server."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["error", "requestId"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          },
          "requestId": {
            "type": "string"
          }
        }
      }
    }
  }
}
