openapi: 3.0.3
info:
  title: Zolltarifnummern API
  description: |
    API for searching customs tariff numbers (Combined Nomenclature / CN codes),
    customs offices, and customs definitions.
    
    This is the V1 API using traditional text matching (no embeddings).
  version: '1.2'
  contact:
    url: https://www.zolltarifnummern.de

servers:
  - url: https://www.zolltarifnummern.de/api/v1
    description: Production

paths:
  /cnSuggest:
    get:
      summary: Search customs tariff numbers
      description: |
        Search for customs tariff numbers by number or description.
        - Numeric search: Prefix match on cn_char
        - Text search: Match + Wildcard + Fuzzy on description
        
        **Example URL:**
        ```
        https://www.zolltarifnummern.de/api/v1/cnSuggest?term=fresh%20beef&year=2026&lang=en
        ```
      operationId: cnSuggest
      tags:
        - Customs Tariff
      parameters:
        - name: term
          in: query
          required: true
          description: Search term (number or text)
          schema:
            type: string
            minLength: 1
            maxLength: 100
          examples:
            number:
              value: "02075110"
              summary: Search by tariff number
            text:
              value: "fresh beef"
              summary: Text search in description
        - name: year
          in: query
          required: false
          description: Nomenclature year
          schema:
            type: integer
            minimum: 2020
            maximum: 2030
            default: 2026
          example: 2026
        - name: lang
          in: query
          required: false
          description: Language
          schema:
            type: string
            enum: [de, en, fr]
            default: de
          example: de
      responses:
        '200':
          description: Search results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CnSuggestResponse'
              examples:
                numeric:
                  summary: Numeric search
                  value:
                    query: "02075110"
                    year: "2026"
                    lang: "de"
                    version: "1.2"
                    total: 1
                    suggestions:
                      - code: "02075110"
                        score: 1.0
                        value: "<span><em>02075110</em></span> Geese, whole, fresh"
                        data: "https://www.zolltarifnummern.de/2026/02075110"
                text:
                  summary: Text search
                  value:
                    query: "fresh beef"
                    year: "2026"
                    lang: "en"
                    version: "1.2"
                    total: 10
                    suggestions:
                      - code: "02013000"
                        score: 12.5
                        value: "<span>02013000</span> Meat of bovine animals, boneless, <em>fresh</em>"
                        data: "https://www.zolltarifnummern.de/2026/02013000"
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
        '429':
          description: Rate limit exceeded (50 requests per minute)
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
              description: Request limit per minute
            X-RateLimit-Remaining:
              schema:
                type: integer
              description: Remaining requests
            Retry-After:
              schema:
                type: integer
              description: Seconds until rate limit resets
        '503':
          description: Elasticsearch unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchError'

  /cnDuties:
    get:
      summary: Get duty rates
      description: |
        Returns duty rates and trade measures for a customs tariff number.
        Includes third-country duties, preferential rates, and trade restrictions.
        
        **Example URL:**
        ```
        https://www.zolltarifnummern.de/api/v1/cnDuties?term=02075110&year=2026
        ```
      operationId: cnDuties
      tags:
        - Customs Tariff
      parameters:
        - name: term
          in: query
          required: true
          description: Customs tariff number (8-10 digits)
          schema:
            type: string
            pattern: '^\d{8,10}$'
          example: "02075110"
        - name: year
          in: query
          required: false
          description: Nomenclature year
          schema:
            type: integer
            minimum: 2020
            maximum: 2030
            default: 2026
          example: 2026
      responses:
        '200':
          description: Duty rates and measures
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CnDutiesResponse'
              example:
                query: "02075110"
                year: "2026"
                total: 3
                duties:
                  - goods_code: "0207511000"
                    goods_code_cn: "02075110"
                    add_code: "0000"
                    order_no: "001"
                    start_date: "2024-01-01"
                    end_date: "2099-12-31"
                    red_ind: null
                    origin: "ERGA OMNES"
                    measure_type: "Third country duty"
                    legal_base: "R2658/87"
                    duty: "12.8%"
                    origin_code: "1011"
                    meas_type_code: "103"
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
        '429':
          description: Rate limit exceeded (10 requests per minute)
        '503':
          description: Service unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchError'

  /officesSuggest:
    get:
      summary: Search customs offices
      description: |
        Search for customs offices by reference number, city, or name.
        Returns up to 6 matching offices.
        
        **Example URL:**
        ```
        https://www.zolltarifnummern.de/api/v1/officesSuggest?term=Hamburg
        ```
      operationId: officesSuggest
      tags:
        - Customs Offices
      parameters:
        - name: term
          in: query
          required: true
          description: Search term (reference number, city, or office name)
          schema:
            type: string
            minLength: 1
            maxLength: 100
          examples:
            ref_number:
              value: "DE003200"
              summary: Search by reference number
            city:
              value: "Hamburg"
              summary: Search by city
            name:
              value: "Hauptzollamt"
              summary: Search by office name
      responses:
        '200':
          description: Search results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OfficesSuggestResponse'
              examples:
                found:
                  summary: Offices found
                  value:
                    query: "Hamburg"
                    total: 3
                    suggestions:
                      - ref_number: "DE003200"
                        value: "DE003200<br>Hauptzollamt Hamburg (Hamburg)"
                        data: "https://www.zolltarifnummern.de/zollstellen/DE003200"
                      - ref_number: "DE003201"
                        value: "DE003201<br>Zollamt Hamburg-Hafen (Hamburg)"
                        data: "https://www.zolltarifnummern.de/zollstellen/DE003201"
                empty:
                  summary: No results
                  value:
                    query: "xyz123"
                    total: 0
                    suggestions: []
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
        '429':
          description: Rate limit exceeded (50 requests per minute)
        '503':
          description: Service unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchError'

  /definitionsSuggest:
    get:
      summary: Search definitions
      description: |
        Search for customs-related definitions and terms.
        Returns up to 10 matching definitions.
        
        **Example URL:**
        ```
        https://www.zolltarifnummern.de/api/v1/definitionsSuggest?term=Inflation&lang=de
        ```
      operationId: definitionsSuggest
      tags:
        - Definitions
      parameters:
        - name: term
          in: query
          required: true
          description: Search term
          schema:
            type: string
            minLength: 1
            maxLength: 100
          examples:
            inflation:
              value: "Inflation"
              summary: Search for inflation
            zoll:
              value: "Zollwert"
              summary: Search for customs value
        - name: lang
          in: query
          required: false
          description: Language
          schema:
            type: string
            enum: [de, en, fr]
            default: de
          example: de
      responses:
        '200':
          description: Search results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DefinitionsSuggestResponse'
              examples:
                found:
                  summary: Definitions found
                  value:
                    query: "Inflation"
                    lang: "de"
                    total: 2
                    suggestions:
                      - value: "Inflation"
                        data: "https://www.zolltarifnummern.de/info/definitionen/456"
                      - value: "Inflationsrate"
                        data: "https://www.zolltarifnummern.de/info/definitionen/457"
                empty:
                  summary: No results
                  value:
                    query: "xyz123"
                    lang: "de"
                    total: 0
                    suggestions: []
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
        '429':
          description: Rate limit exceeded (50 requests per minute)
        '503':
          description: Service unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchError'

components:
  schemas:
    CnSuggestResponse:
      type: object
      required:
        - query
        - year
        - lang
        - version
        - total
        - suggestions
      properties:
        query:
          type: string
          description: Sanitized search term
          example: "fresh beef"
        year:
          type: string
          description: Year
          example: "2026"
        lang:
          type: string
          description: Language
          enum: [de, en, fr]
          example: "de"
        version:
          type: string
          description: API version
          example: "1.2"
        total:
          type: integer
          description: Number of results
          example: 10
        suggestions:
          type: array
          items:
            $ref: '#/components/schemas/CnSuggestion'
    
    CnSuggestion:
      type: object
      properties:
        code:
          type: string
          description: Customs tariff number (8 digits)
          example: "02013000"
        score:
          type: number
          format: float
          description: Relevance score
          example: 12.5
        value:
          type: string
          description: Formatted display with HTML highlighting
          example: "<span>02013000</span> Meat of bovine animals, <em>fresh</em>"
        data:
          type: string
          format: uri
          description: URL to detail page
          example: "https://www.zolltarifnummern.de/2026/02013000"

    CnDutiesResponse:
      type: object
      properties:
        query:
          type: string
          description: Tariff number
          example: "02075110"
        year:
          type: string
          description: Year
          example: "2026"
        total:
          type: integer
          description: Number of duty entries
          example: 5
        duties:
          type: array
          items:
            $ref: '#/components/schemas/DutyEntry'

    DutyEntry:
      type: object
      properties:
        goods_code:
          type: string
          description: Full goods code (10 digits)
          example: "0207511000"
        goods_code_cn:
          type: string
          description: CN code (8 digits)
          example: "02075110"
        add_code:
          type: string
          description: Additional code
          example: "0000"
        order_no:
          type: string
          description: Order number
          example: "001"
        start_date:
          type: string
          format: date
          description: Measure start date
          example: "2024-01-01"
        end_date:
          type: string
          format: date
          description: Measure end date
          example: "2099-12-31"
        red_ind:
          type: string
          nullable: true
          description: Reduction indicator
        origin:
          type: string
          description: Origin country/region name
          example: "ERGA OMNES"
        measure_type:
          type: string
          description: Measure type description
          example: "Third country duty"
        legal_base:
          type: string
          description: Legal base regulation
          example: "R2658/87"
        duty:
          type: string
          description: Duty rate
          example: "12.8%"
        origin_code:
          type: string
          description: Origin code
          example: "1011"
        meas_type_code:
          type: string
          description: Measure type code
          example: "103"

    OfficesSuggestResponse:
      type: object
      properties:
        query:
          type: string
          description: Search term
          example: "Hamburg"
        total:
          type: integer
          description: Number of results
          example: 3
        suggestions:
          type: array
          items:
            $ref: '#/components/schemas/OfficeSuggestion'

    OfficeSuggestion:
      type: object
      properties:
        ref_number:
          type: string
          description: Office reference number
          example: "DE003200"
        value:
          type: string
          description: Formatted display with HTML
          example: "DE003200<br>Hauptzollamt Hamburg (Hamburg)"
        data:
          type: string
          format: uri
          description: URL to detail page
          example: "https://www.zolltarifnummern.de/zollstellen/DE003200"

    DefinitionsSuggestResponse:
      type: object
      properties:
        query:
          type: string
          description: Search term
          example: "Inflation"
        lang:
          type: string
          description: Language
          example: "de"
        total:
          type: integer
          description: Number of results
          example: 2
        suggestions:
          type: array
          items:
            $ref: '#/components/schemas/DefinitionSuggestion'

    DefinitionSuggestion:
      type: object
      properties:
        value:
          type: string
          description: Definition term
          example: "Inflation"
        data:
          type: string
          format: uri
          description: URL to detail page
          example: "https://www.zolltarifnummern.de/info/definitionen/456"
    
    ValidationError:
      type: object
      properties:
        message:
          type: string
          example: "The given data was invalid."
        errors:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          example:
            term: ["The term field is required."]
    
    SearchError:
      type: object
      properties:
        query:
          type: string
        year:
          type: string
        total:
          type: integer
          example: 0
        error:
          type: string
          example: "Service unavailable"

  securitySchemes:
    rateLimiting:
      type: apiKey
      in: header
      name: X-RateLimit-Limit
      description: |
        Rate limits per endpoint:
        - /cnSuggest: 50 requests/minute
        - /officesSuggest: 50 requests/minute
        - /definitionsSuggest: 50 requests/minute
        - /cnDuties: 10 requests/minute

tags:
  - name: Customs Tariff
    description: Customs tariff number operations (CN codes)
  - name: Customs Offices
    description: Customs office search
  - name: Definitions
    description: Customs terminology and definitions
