{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://example.org/schemas/atproto-lexicon.json",
  "title": "AT Protocol Lexicon",
  "description": "JSON Schema for AT Protocol Lexicon definitions.",
  "type": "object",
  "properties": {
    "lexicon": {
      "type": "number",
      "description": "The lexicon version number (currently 1).",
      "enum": [1]
    },
    "id": {
      "type": "string",
      "description": "A unique identifier for this lexicon (e.g., 'app.bsky.feed.post').",
      "pattern": "^([A-Za-z0-9_-]+\\.)*([A-Za-z0-9_-]+)$"
    },
    "revision": {
      "type": "integer",
      "description": "Incrementing revision number.",
      "minimum": 1
    },
    "description": {
      "type": "string",
      "description": "Optional description of this lexicon."
    },
    "defs": {
      "type": "object",
      "description": "A mapping of definition names to definition objects.",
      "properties": {
        "main": {
          "$ref": "#/definitions/mainDefinition"
        }
      },
      "additionalProperties": {
        "$ref": "#/definitions/additionalDefinition"
      },
      "minProperties": 1
    }
  },
  "required": ["lexicon", "id", "defs"],
  "additionalProperties": true,
  "definitions": {
    "mainDefinition": {
      "oneOf": [
        { "$ref": "#/definitions/recordDef" },
        { "$ref": "#/definitions/objectDef" },
        { "$ref": "#/definitions/xrpc.queryDef" },
        { "$ref": "#/definitions/xrpc.procedureDef" },
        { "$ref": "#/definitions/xrpc.subscriptionDef" },
        { "$ref": "#/definitions/tokenDef" },
        { "$ref": "#/definitions/primitiveDef" },
        { "$ref": "#/definitions/ipldTypeDef" },
        { "$ref": "#/definitions/blobDef" },
        { "$ref": "#/definitions/propertyArrayDef" }
      ]
    },
    "additionalDefinition": {
      "oneOf": [
        { "$ref": "#/definitions/objectDef" },
        { "$ref": "#/definitions/tokenDef" },
        { "$ref": "#/definitions/primitiveDef" },
        { "$ref": "#/definitions/ipldTypeDef" },
        { "$ref": "#/definitions/blobDef" },
        { "$ref": "#/definitions/propertyArrayDef" }
      ]
    },
    "recordDef": {
      "type": "object",
      "description": "Describes a record definition.",
      "properties": {
        "type": {
          "type": "string",
          "const": "record"
        },
        "description": {
          "type": "string"
        },
        "key": {
          "type": "string",
          "description": "Record key type.\n\n- 'tid' - A unique id containing a timestamp https://atproto.com/specs/tid\n- 'nsid' - For cases when the record must be a valid NSID https://atproto.com/specs/nsid\n- 'literal:value' - This key type is used when there should be only a single record in the collection, with a fixed, well-known Record Key. The most common value is self, specified as literal:self in a Lexicon schema.\n- any string (custom)",
          "pattern": "tid|nsid|[a-zA-Z0-9.-_:~]{1,512}",
          "minLength": 1,
          "maxLength": 512
        },
        "record": {
          "$ref": "#/definitions/objectDef"
        }
      },
      "required": ["type"],
      "additionalProperties": false
    },
    "objectDef": {
      "type": "object",
      "description": "Describes an object definition.",
      "properties": {
        "type": {
          "type": "string",
          "const": "object"
        },
        "description": {
          "type": "string"
        },
        "properties": {
          "type": "object",
          "description": "A mapping of property names to schema types.",
          "additionalProperties": {
            "oneOf": [
              { "$ref": "#/definitions/propertyDef" },
              { "$ref": "#/definitions/propertyArrayDef" }
            ]
          }
        },
        "required": {
          "type": "array",
          "description": "List of required property names.",
          "items": {
            "type": "string"
          }
        }
      },
      "required": ["type", "properties"]
    },
    "xrpc.queryDef": {
      "type": "object",
      "description": "Describes a query definition.",
      "properties": {
        "type": {
          "type": "string",
          "const": "query"
        },
        "description": {
          "type": "string"
        },
        "parameters": {
          "$ref": "#/definitions/xrpc.parametersDef"
        },
        "output": {
          "$ref": "#/definitions/xrpc.bodyDef"
        },
        "errors": {
          "$ref": "#/definitions/xrpc.errorsDef"
        }
      },
      "required": ["type"],
      "additionalProperties": false
    },
    "xrpc.procedureDef": {
      "type": "object",
      "description": "Describes a procedure definition.",
      "properties": {
        "type": {
          "type": "string",
          "const": "procedure"
        },
        "description": {
          "type": "string"
        },
        "parameters": {
          "$ref": "#/definitions/xrpc.parametersDef"
        },
        "input": {
          "$ref": "#/definitions/xrpc.bodyDef"
        },
        "output": {
          "$ref": "#/definitions/xrpc.bodyDef"
        },
        "errors": {
          "$ref": "#/definitions/xrpc.errorsDef"
        }
      },
      "required": ["type"],
      "additionalProperties": false
    },
    "xrpc.subscriptionDef": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "subscription"
        },
        "description": {
          "type": "string"
        },
        "parameters": {
          "$ref": "#/definitions/xrpc.parametersDef"
        },
        "message": {
          "$ref": "#/definitions/xrpc.subscriptionMessageDef"
        },
        "errors": {
          "$ref": "#/definitions/xrpc.errorsDef"
        }
      }
    },
    "xrpc.parametersDef": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "params"
        },
        "properties": {
          "type": "object",
          "description": "Describes the HTTP query parameters for this endpoint.",
          "additionalProperties": {
            "oneOf": [
              { "$ref": "#/definitions/primitiveDef" },
              { "$ref": "#/definitions/primitiveArrayDef" }
            ]
          }
        },
        "required": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "List of required property names."
        }
      },
      "additionalProperties": false
    },
    "xrpc.bodyDef": {
      "type": "object",
      "properties": {
        "schema": {
          "oneOf": [
            { "$ref": "#/definitions/objectDef" },
            { "$ref": "#/definitions/refDef" }
          ]
        },
        "encoding": {
          "type": "string",
          "description": "The mime type for body contents",
          "examples": ["application/json"],
          "pattern": "^.*/.*$"
        },
        "description": {
          "type": "string"
        }
      },
      "required": ["encoding"],
      "additionalProperties": false
    },
    "xrpc.errorsDef": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Short name for the error type, with no whitespace"
          },
          "description": {
            "type": "string"
          }
        },
        "required": ["name"],
        "additionalProperties": false
      }
    },
    "xrpc.subscriptionMessageDef": {
      "type": "object",
      "properties": {
        "schema": {
          "oneOf": [
            { "$ref": "#/definitions/objectDef" },
            { "$ref": "#/definitions/refDef" }
          ]
        },
        "description": {
          "type": "string"
        }
      }
    },
    "primitives.booleanDef": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "boolean"
        },
        "description": {
          "type": "string"
        },
        "default": {
          "type": "boolean"
        },
        "const": {
          "type": "boolean"
        }
      },
      "required": ["type"],
      "additionalProperties": false
    },
    "primitives.integerDef": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "integer"
        },
        "description": {
          "type": "string"
        },
        "default": {
          "type": "integer"
        },
        "minimum": {
          "type": "integer"
        },
        "maximum": {
          "type": "integer"
        },
        "enum": {
          "type": "array",
          "items": {
            "type": "integer"
          }
        },
        "const": {
          "type": "integer"
        }
      },
      "required": ["type"],
      "additionalProperties": false
    },
    "primitives.stringDef": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "string"
        },
        "format": {
          "type": "string",
          "enum": [
            "datetime",
            "uri",
            "at-uri",
            "did",
            "handle",
            "at-identifier",
            "nsid",
            "cid",
            "language",
            "tid",
            "record-key"
          ],
          "description": "https://atproto.com/specs/lexicon#string-formats"
        },
        "description": {
          "type": "string"
        },
        "default": {
          "type": "string"
        },
        "minLength": {
          "type": "integer"
        },
        "maxLength": {
          "type": "integer"
        },
        "minGraphemes": {
          "type": "integer"
        },
        "maxGraphemes": {
          "type": "integer"
        },
        "enum": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "const": {
          "type": "string"
        },
        "knownValues": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "required": ["type"],
      "additionalProperties": false
    },
    "primitives.unknownDef": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "unknown"
        },
        "description": {
          "type": "string"
        }
      },
      "required": ["type"],
      "additionalProperties": false
    },
    "primitiveDef": {
      "oneOf": [
        { "$ref": "#/definitions/primitives.booleanDef" },
        { "$ref": "#/definitions/primitives.integerDef" },
        { "$ref": "#/definitions/primitives.stringDef" },
        { "$ref": "#/definitions/primitives.unknownDef" }
      ]
    },
    "primitiveArrayDef": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "array"
        },
        "items": {
          "$ref": "#/definitions/primitiveDef"
        },
        "description": {
          "type": "string"
        },
        "minLength": {
          "type": "integer"
        },
        "maxLength": {
          "type": "integer"
        }
      },
      "required": ["type", "items"],
      "additionalProperties": false
    },
    "ipld.bytesDef": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "bytes"
        },
        "description": {
          "type": "string"
        },
        "minLength": {
          "type": "integer"
        },
        "maxLength": {
          "type": "integer"
        }
      },
      "required": ["type"],
      "additionalProperties": false
    },
    "ipld.cidLinkDef": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "cid-link"
        },
        "description": {
          "type": "string"
        }
      },
      "required": ["type"],
      "additionalProperties": false
    },
    "ipldTypeDef": {
      "oneOf": [
        { "$ref": "#/definitions/ipld.bytesDef" },
        { "$ref": "#/definitions/ipld.cidLinkDef" }
      ]
    },
    "ref.refDef": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "ref"
        },
        "description": {
          "type": "string"
        },
        "ref": {
          "type": "string",
          "description": "Reference to another schema definition",
          "examples": ["com.atproto.repo.strongRef"]
        }
      },
      "required": ["type", "ref"],
      "additionalProperties": false
    },
    "ref.unionDef": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "union"
        },
        "description": {
          "type": "string"
        },
        "refs": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "References to schema definitions"
        },
        "closed": {
          "type": "boolean",
          "description": "indicates if a union is \"open\" or \"closed\"",
          "default": false
        }
      },
      "required": ["type", "refs"],
      "additionalProperties": false
    },
    "refDef": {
      "oneOf": [
        { "$ref": "#/definitions/ref.refDef" },
        { "$ref": "#/definitions/ref.unionDef" }
      ]
    },
    "blobDef": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "blob"
        },
        "description": {
          "type": "string"
        },
        "accept": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "List of acceptable MIME types. Each may end in * as a glob pattern (eg, image/*).",
          "default": ["*/*"]
        },
        "maxSize": {
          "type": "integer",
          "description": "Maximum size in bytes"
        }
      },
      "required": ["type"],
      "additionalProperties": false
    },
    "propertyDef": {
      "oneOf": [
        { "$ref": "#/definitions/primitiveDef" },
        { "$ref": "#/definitions/ipldTypeDef" },
        { "$ref": "#/definitions/refDef" },
        { "$ref": "#/definitions/blobDef" }
      ]
    },
    "propertyArrayDef": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "array"
        },
        "items": {
          "$ref": "#/definitions/propertyDef"
        },
        "description": {
          "type": "string"
        },
        "minLength": {
          "type": "integer"
        },
        "maxLength": {
          "type": "integer"
        }
      },
      "required": ["type", "items"],
      "additionalProperties": false
    },
    "tokenDef": {
      "type": "object",
      "description": "Tokens are empty data values which exist only to be referenced by name. Tokens are similar to the concept of a \"symbol\" in some programming languages, distinct from strings, variables, built-in keywords, or other identifiers.",
      "properties": {
        "type": {
          "type": "string",
          "const": "token"
        },
        "description": {
          "type": "string"
        }
      },
      "required": ["type"]
    }
  }
}
