{
  "openapi": "3.1.0",
  "info": {
    "title": "Zoek Belastingkenmerk API",
    "version": "1.0.0",
    "summary": "Convert a Dutch Belastingdienst betalingskenmerk to an aanslagnummer and back.",
    "description": "Free, key-less, CORS-enabled JSON API that converts between a Dutch Belastingdienst `betalingskenmerk` (16-digit payment reference) and the underlying `aanslagnummer` (assessment number). Conversion follows the official specification \"Betalingskenmerk bepaling v1.5\". No personal data is stored or logged. Independent tool, not an official Belastingdienst service.",
    "license": { "name": "MIT" },
    "contact": { "url": "https://zoek-belastingkenmerk.nl/" }
  },
  "servers": [
    { "url": "https://zoek-belastingkenmerk.nl", "description": "Production" }
  ],
  "externalDocs": {
    "description": "Human-readable documentation and live tool",
    "url": "https://zoek-belastingkenmerk.nl/#api"
  },
  "tags": [
    { "name": "convert", "description": "Conversion between betalingskenmerk and aanslagnummer." }
  ],
  "paths": {
    "/api/v1": {
      "get": {
        "operationId": "getApiInfo",
        "tags": ["convert"],
        "summary": "Machine-readable API description",
        "description": "Returns a JSON description of all available endpoints.",
        "responses": {
          "200": {
            "description": "API info",
            "content": { "application/json": { "schema": { "type": "object" } } }
          }
        }
      }
    },
    "/api/v1/convert": {
      "get": {
        "operationId": "convert",
        "tags": ["convert"],
        "summary": "Auto-detect direction and convert",
        "description": "Detects direction from the input: letters present → encode an aanslagnummer into a betalingskenmerk; only digits → decode a betalingskenmerk into its tax fields.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "A betalingskenmerk (16 digits) or an aanslagnummer (9 digits + 1 letter + 7 digits). Spaces and separators are ignored.",
            "schema": { "type": "string", "examples": ["2036000016301110", "036000012L0123110"] }
          },
          { "$ref": "#/components/parameters/lang" }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/ConvertOk" },
          "400": { "$ref": "#/components/responses/Error" },
          "422": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/v1/decode": {
      "get": {
        "operationId": "decode",
        "tags": ["convert"],
        "summary": "Decode a betalingskenmerk",
        "description": "Decodes a 16-digit betalingskenmerk into BSN/RSIN, tax type, year and period.",
        "parameters": [
          {
            "name": "kenmerk",
            "in": "query",
            "required": true,
            "description": "A 16-digit betalingskenmerk. Spaces are ignored.",
            "schema": { "type": "string", "pattern": "^[0-9 ]{16,19}$", "examples": ["2036000016301110"] }
          },
          { "$ref": "#/components/parameters/lang" }
        ],
        "responses": {
          "200": {
            "description": "Decoded fields",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DecodeResult" } } }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "422": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/v1/encode": {
      "get": {
        "operationId": "encode",
        "tags": ["convert"],
        "summary": "Encode an aanslagnummer",
        "description": "Builds the 16-digit betalingskenmerk for a given aanslagnummer.",
        "parameters": [
          {
            "name": "aanslag",
            "in": "query",
            "required": true,
            "description": "An aanslagnummer: 9 digits + 1 letter + 7 digits.",
            "schema": { "type": "string", "examples": ["036000012L0123110"] }
          }
        ],
        "responses": {
          "200": {
            "description": "The betalingskenmerk",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EncodeResult" } } }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "422": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/v1/validate": {
      "get": {
        "operationId": "validate",
        "tags": ["convert"],
        "summary": "Validate the control digit",
        "description": "Checks only whether the modulus-11 control digit (elfproef) of a betalingskenmerk is valid.",
        "parameters": [
          {
            "name": "kenmerk",
            "in": "query",
            "required": true,
            "description": "A 16-digit betalingskenmerk. Spaces are ignored.",
            "schema": { "type": "string", "examples": ["2036000016301110"] }
          }
        ],
        "responses": {
          "200": {
            "description": "Validation result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean" },
                    "valid": { "type": "boolean" },
                    "kenmerk": { "type": "string" }
                  }
                }
              }
            }
          },
          "422": { "$ref": "#/components/responses/Error" }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "lang": {
        "name": "lang",
        "in": "query",
        "required": false,
        "description": "Language of the human-readable descriptions.",
        "schema": { "type": "string", "enum": ["nl", "en"], "default": "nl" }
      }
    },
    "responses": {
      "ConvertOk": {
        "description": "Conversion result (shape depends on detected direction)",
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                { "$ref": "#/components/schemas/DecodeResult" },
                { "$ref": "#/components/schemas/EncodeResult" }
              ]
            }
          }
        }
      },
      "Error": {
        "description": "Invalid or unprocessable input",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "ok": { "type": "boolean", "const": false },
                "error": { "type": "string" }
              },
              "required": ["ok", "error"]
            }
          }
        }
      }
    },
    "schemas": {
      "DecodeResult": {
        "type": "object",
        "description": "Decoded betalingskenmerk fields.",
        "properties": {
          "ok": { "type": "boolean" },
          "betalingskenmerk": { "type": "string", "description": "Formatted in groups of four, e.g. \"2036 0000 1630 1110\"." },
          "controleOk": { "type": "boolean", "description": "Whether the modulus-11 control digit is valid." },
          "direction": { "type": "string", "enum": ["kenmerk->aanslag"], "description": "Present on /convert responses." },
          "middel": { "type": "string", "description": "Tax-type letter (A, B, F, L, V, H, N, P, W, M, Y, Z, T, C)." },
          "middelOmschrijving": { "type": "string", "description": "Human-readable description of the tax type." },
          "soort": { "type": ["string", "null"], "description": "Tax category, e.g. Loonbelasting, Omzetbelasting." },
          "kind": { "type": ["string", "null"], "description": "Assessment kind, e.g. Aangifte, Naheffingsaanslag." },
          "categorie": { "type": ["string", "null"], "description": "Bookkeeping category hint." },
          "aanslagnummer": { "type": ["string", "null"], "description": "Reconstructed dotted aanslagnummer where fully recoverable (e.g. for M/Y)." },
          "bsn": { "type": ["string", "null"], "description": "9-digit BSN/RSIN, or null if not recoverable." },
          "jaartalDigit": { "type": "string" },
          "jaartal": { "type": "integer", "description": "Inferred 4-digit year." },
          "tijdvakCode": { "type": ["string", "null"] },
          "tijdvak": { "type": ["string", "null"], "description": "Human-readable period, e.g. November, Q3, Hele jaar." },
          "middelherkenning": { "type": ["string", "null"] },
          "omschrijving": { "type": "string", "description": "Combined human-readable summary." }
        },
        "required": ["ok"]
      },
      "EncodeResult": {
        "type": "object",
        "description": "Encoded aanslagnummer result.",
        "properties": {
          "ok": { "type": "boolean" },
          "betalingskenmerk": { "type": "string", "description": "The 16-digit payment reference." },
          "direction": { "type": "string", "enum": ["aanslag->kenmerk"], "description": "Present on /convert responses." }
        },
        "required": ["ok"]
      }
    }
  }
}
