openapi: 3.1.0
info:
  title: SupplyChainService API
  version: 1.0.0
security:
  - WorldMonitorKey: []
  - ApiKeyHeader: []
servers:
  - url: https://api.worldmonitor.app
paths:
  /api/supply-chain/v1/get-shipping-rates:
    get:
      tags:
        - SupplyChainService
      summary: GetShippingRates
      description: >-
        GetShippingRates returns current container shipping-rate indices;
        upstream_unavailable is set when the source could not be reached.
      operationId: GetShippingRates
      parameters:
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                fetchedAt: '2026-01-15T12:00:00Z'
                indices:
                  - changePct: 1.5
                    currentValue: 1.5
                    history:
                      - date: '2026-01-15'
                        value: 1.5
                    indexId: example-id
                    name: WorldMonitor Analyst
                upstreamUnavailable: true
              schema:
                $ref: '#/components/schemas/GetShippingRatesResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/get-chokepoint-status:
    get:
      tags:
        - SupplyChainService
      summary: GetChokepointStatus
      description: >-
        GetChokepointStatus retrieves seeded chokepoint status. Empty
        chokepoints
         with upstream_unavailable=true means the seed snapshot is unavailable/
         degraded, not that there are confirmed zero chokepoints.
      operationId: GetChokepointStatus
      parameters:
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                chokepoints:
                  - activeWarnings: 1
                    affectedRoutes:
                      - example
                    aisDisruptions: 1
                    congestionLevel: example
                    description: Example WorldMonitor observation.
                fetchedAt: '2026-01-15T12:00:00Z'
                upstreamUnavailable: true
              schema:
                $ref: '#/components/schemas/GetChokepointStatusResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/get-chokepoint-history:
    get:
      tags:
        - SupplyChainService
      summary: GetChokepointHistory
      description: >-
        GetChokepointHistory returns transit-count history for a single
        chokepoint,
         loaded lazily on card expand. Keeps the status RPC compact (no 180-day
         history per chokepoint on every call).
      operationId: GetChokepointHistory
      parameters:
        - name: chokepointId
          in: query
          description: Chokepoint identifier whose transit history should be returned.
          required: true
          example: suez
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                chokepointId: suez
                fetchedAt: '1717200000000'
                history:
                  - capContainer: 1.5
                    capDryBulk: 1.5
                    capGeneralCargo: 1.5
                    capRoro: 1.5
                    capTanker: 1.5
              schema:
                $ref: '#/components/schemas/GetChokepointHistoryResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/get-critical-minerals:
    get:
      tags:
        - SupplyChainService
      summary: GetCriticalMinerals
      description: >-
        GetCriticalMinerals returns critical-minerals supply indicators;
        upstream_unavailable is set when the source could not be reached.
      operationId: GetCriticalMinerals
      parameters:
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                fetchedAt: '2026-01-15T12:00:00Z'
                minerals:
                  - globalProduction: 1.5
                    hhi: 1.5
                    mineral: example
                    riskRating: example
                    topProducers:
                      - country: US
                        countryCode: US
                        productionTonnes: 1.5
                        sharePct: 1.5
                upstreamUnavailable: true
              schema:
                $ref: '#/components/schemas/GetCriticalMineralsResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/get-shipping-stress:
    get:
      tags:
        - SupplyChainService
      summary: GetShippingStress
      description: >-
        GetShippingStress returns carrier market data and a composite stress
        index.
      operationId: GetShippingStress
      parameters:
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                carriers:
                  - carrierType: all
                    changePct: 1.5
                    name: WorldMonitor Analyst
                    price: 75.25
                    sparkline:
                      - 1.5
                fetchedAt: 1717200000000
                stressLevel: example
                stressScore: 42.5
                upstreamUnavailable: true
              schema:
                $ref: '#/components/schemas/GetShippingStressResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/get-country-chokepoint-index:
    get:
      tags:
        - SupplyChainService
      summary: GetCountryChokepointIndex
      description: >-
        GetCountryChokepointIndex returns per-chokepoint exposure scores for a
        country. PRO-gated. Requires entitlement tier >= 1.
      operationId: GetCountryChokepointIndex
      security:
        - WorldMonitorKey: []
        - ApiKeyHeader: []
        - BearerAuth: []
      parameters:
        - name: iso2
          in: query
          description: ISO 3166-1 alpha-2 country code (uppercase).
          required: true
          example: US
          schema:
            type: string
            pattern: ^[A-Z]{2}$
        - name: hs2
          in: query
          description: >-
            HS2 chapter (2-digit string). Defaults to "27" (energy/mineral
            fuels) when absent.
          required: false
          example: '27'
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                exposures:
                  - chokepointId: suez
                    chokepointName: WorldMonitor Analyst
                    coastSide: example
                    exposureScore: 42.5
                    shockSupported: true
                fetchedAt: '2026-01-15T12:00:00Z'
                hs2: '27'
                iso2: US
                primaryChokepointId: suez
              schema:
                $ref: '#/components/schemas/GetCountryChokepointIndexResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: PRO entitlement access denied.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/get-bypass-options:
    get:
      tags:
        - SupplyChainService
      summary: GetBypassOptions
      description: >-
        GetBypassOptions returns ranked bypass corridors for a chokepoint.
        PRO-gated. Requires entitlement tier >= 1.
      operationId: GetBypassOptions
      security:
        - WorldMonitorKey: []
        - ApiKeyHeader: []
        - BearerAuth: []
      parameters:
        - name: chokepointId
          in: query
          description: Chokepoint identifier to evaluate for bypass options.
          required: true
          example: suez
          schema:
            type: string
        - name: cargoType
          in: query
          description: 'container | tanker | bulk | roro  (default: "container")'
          required: false
          example: container
          schema:
            type: string
        - name: closurePct
          in: query
          description: '0-100, percent of capacity blocked (default: 100)'
          required: false
          example: 1
          schema:
            type: integer
            format: int32
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                cargoType: container
                chokepointId: suez
                closurePct: 1
                fetchedAt: '2026-01-15T12:00:00Z'
                options:
                  - activationThreshold: example
                    addedCostMultiplier: 75.25
                    addedTransitDays: 7
                    bypassWarRiskTier: WAR_RISK_TIER_NORMAL
                    capacityConstraintTonnage: '1717200000000'
              schema:
                $ref: '#/components/schemas/GetBypassOptionsResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: PRO entitlement access denied.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/get-country-cost-shock:
    get:
      tags:
        - SupplyChainService
      summary: GetCountryCostShock
      description: >-
        GetCountryCostShock returns cost shock and war risk data for a
        country+chokepoint. PRO-gated. Requires entitlement tier >= 1.
      operationId: GetCountryCostShock
      security:
        - WorldMonitorKey: []
        - ApiKeyHeader: []
        - BearerAuth: []
      parameters:
        - name: iso2
          in: query
          description: ISO 3166-1 alpha-2 country code for the importing country.
          required: true
          example: US
          schema:
            type: string
            pattern: ^[A-Z]{2}$
        - name: chokepointId
          in: query
          description: Chokepoint identifier to model as disrupted.
          required: true
          example: suez
          schema:
            type: string
        - name: hs2
          in: query
          description: 'HS2 chapter (default: "27")'
          required: false
          example: '27'
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                chokepointId: suez
                coverageDays: 7
                fetchedAt: '2026-01-15T12:00:00Z'
                hasEnergyModel: true
                hs2: '27'
              schema:
                $ref: '#/components/schemas/GetCountryCostShockResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: PRO entitlement access denied.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/get-country-products:
    get:
      tags:
        - SupplyChainService
      summary: GetCountryProducts
      description: >-
        GetCountryProducts returns the seeded bilateral-HS4 import basket for a
        country. PRO-gated. Requires entitlement tier >= 1.
      operationId: GetCountryProducts
      security:
        - WorldMonitorKey: []
        - ApiKeyHeader: []
        - BearerAuth: []
      parameters:
        - name: iso2
          in: query
          description: >-
            ISO 3166-1 alpha-2 country code whose strategic products should be
            returned.
          required: true
          example: US
          schema:
            type: string
            pattern: ^[A-Z]{2}$
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                fetchedAt: '2026-01-15T12:00:00Z'
                iso2: US
                products:
                  - description: Example WorldMonitor observation.
                    hs4: example
                    topExporters:
                      - partnerCode: 1
                        partnerIso2: US
                        share: 1.5
                        value: 1.5
                    totalValue: 1
                    year: 1
              schema:
                $ref: '#/components/schemas/GetCountryProductsResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: PRO entitlement access denied.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/get-multi-sector-cost-shock:
    get:
      tags:
        - SupplyChainService
      summary: GetMultiSectorCostShock
      description: |-
        GetMultiSectorCostShock returns per-sector cost-shock estimates for a
         country+chokepoint+closure-window. PRO-gated. Requires entitlement tier >= 1.
      operationId: GetMultiSectorCostShock
      security:
        - WorldMonitorKey: []
        - ApiKeyHeader: []
        - BearerAuth: []
      parameters:
        - name: iso2
          in: query
          description: ISO 3166-1 alpha-2 country code for the importing country.
          required: true
          example: US
          schema:
            type: string
            pattern: ^[A-Z]{2}$
        - name: chokepointId
          in: query
          description: Chokepoint identifier to model as disrupted.
          required: true
          example: suez
          schema:
            type: string
        - name: closureDays
          in: query
          description: >-
            Closure-window duration in days. Server clamps to [1, 365]. Defaults
            to 30.
          required: false
          example: 7
          schema:
            type: integer
            format: int32
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                chokepointId: suez
                closureDays: 7
                fetchedAt: '2026-01-15T12:00:00Z'
                iso2: US
                sectors:
                  - addedTransitDays: 7
                    closureDays: 7
                    freightAddedPctPerTon: 1.5
                    hs2: '27'
                    hs2Label: '27'
              schema:
                $ref: '#/components/schemas/GetMultiSectorCostShockResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: PRO entitlement access denied.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/get-sector-dependency:
    get:
      tags:
        - SupplyChainService
      summary: GetSectorDependency
      description: >-
        GetSectorDependency returns dependency flags and risk profile for a
        country+HS2 sector. PRO-gated. Requires entitlement tier >= 1.
      operationId: GetSectorDependency
      security:
        - WorldMonitorKey: []
        - ApiKeyHeader: []
        - BearerAuth: []
      parameters:
        - name: iso2
          in: query
          description: >-
            ISO 3166-1 alpha-2 country code whose sector dependency should be
            analyzed.
          required: true
          example: US
          schema:
            type: string
            pattern: ^[A-Z]{2}$
        - name: hs2
          in: query
          description: HS2 chapter code, e.g. "27" (mineral fuels), "85" (electronics)
          required: true
          example: '27'
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                fetchedAt: '2026-01-15T12:00:00Z'
                flags:
                  - DEPENDENCY_FLAG_SINGLE_SOURCE_CRITICAL
                hasViableBypass: true
                hs2: '27'
                hs2Label: '27'
              schema:
                $ref: '#/components/schemas/GetSectorDependencyResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: PRO entitlement access denied.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/get-route-explorer-lane:
    get:
      tags:
        - SupplyChainService
      summary: GetRouteExplorerLane
      description: >-
        GetRouteExplorerLane returns the primary maritime route, chokepoint
        exposures,
         bypass options with geometry, war risk, and static transit/freight estimates for
         a country pair + HS2 + cargo type. PRO-gated. Wraps the route-intelligence vendor
         endpoint's compute with browser-callable auth and adds fields needed by the
         Route Explorer UI. Requires entitlement tier >= 1.
      operationId: GetRouteExplorerLane
      security:
        - WorldMonitorKey: []
        - ApiKeyHeader: []
        - BearerAuth: []
      parameters:
        - name: fromIso2
          in: query
          description: ISO 3166-1 alpha-2 origin country code for the trade lane.
          required: true
          example: US
          schema:
            type: string
            pattern: ^[A-Z]{2}$
        - name: toIso2
          in: query
          description: ISO 3166-1 alpha-2 destination country code for the trade lane.
          required: true
          example: US
          schema:
            type: string
            pattern: ^[A-Z]{2}$
        - name: hs2
          in: query
          description: HS2 chapter code, e.g. "27", "85"
          required: true
          example: '27'
          schema:
            type: string
        - name: cargoType
          in: query
          description: 'One of: container, tanker, bulk, roro'
          required: true
          example: container
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                bypassOptions:
                  - addedCostMultiplier: 75.25
                    addedTransitDays: 7
                    fromPort:
                      lat: 40.7128
                      lon: -74.006
                    id: example-id
                    name: WorldMonitor Analyst
                cargoType: container
                chokepointExposures:
                  - chokepointId: suez
                    chokepointName: WorldMonitor Analyst
                    exposurePct: 1
                disruptionScore: 42.5
                estFreightUsdPerTeuRange:
                  max: 1
                  min: 1
              schema:
                $ref: '#/components/schemas/GetRouteExplorerLaneResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: PRO entitlement access denied.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/get-route-impact:
    get:
      tags:
        - SupplyChainService
      summary: GetRouteImpact
      description: >-
        GetRouteImpact returns route-level trade exposure: lane value, primary
        exporter concentration, strategic products, resilience score, dependency
        flags, and Comtrade provenance. PRO-gated. Requires entitlement tier >=
        1.
      operationId: GetRouteImpact
      security:
        - WorldMonitorKey: []
        - ApiKeyHeader: []
        - BearerAuth: []
      parameters:
        - name: fromIso2
          in: query
          description: ISO 3166-1 alpha-2 origin country code for the route.
          required: true
          example: US
          schema:
            type: string
            pattern: ^[A-Z]{2}$
        - name: toIso2
          in: query
          description: ISO 3166-1 alpha-2 destination country code for the route.
          required: true
          example: US
          schema:
            type: string
            pattern: ^[A-Z]{2}$
        - name: hs2
          in: query
          description: HS2 chapter code for the product sector on the route.
          required: true
          example: '27'
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                comtradeSource: example
                dependencyFlags:
                  - DEPENDENCY_FLAG_SINGLE_SOURCE_CRITICAL
                fetchedAt: '2026-01-15T12:00:00Z'
                hs2InSeededUniverse: true
                laneValueUsd: 1.5
              schema:
                $ref: '#/components/schemas/GetRouteImpactResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: PRO entitlement access denied.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/list-pipelines:
    get:
      tags:
        - SupplyChainService
      summary: ListPipelines
      description: |-
        ListPipelines returns the curated oil & gas pipeline registry for the
         Energy Atlas PathLayer. Public badges are DERIVED from evidence bundles
         server-side and versioned (classifier_version). Free-tier; see
         docs/methodology/pipelines.mdx for data + classifier spec.
      operationId: ListPipelines
      parameters:
        - name: commodityType
          in: query
          description: Filter to one commodity. Omit (or pass empty) to receive both.
          required: false
          example: oil
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                classifierVersion: example
                fetchedAt: '2026-01-15T12:00:00Z'
                pipelines:
                  - capacityBcmYr: 1.5
                    capacityMbd: 1.5
                    commodityType: oil
                    endPoint:
                      lat: 40.7128
                      lon: -74.006
                    evidence:
                      classifierConfidence: 0.82
                      classifierVersion: example
                      commercialState: example
                      lastEvidenceUpdate: '2026-01-15'
                      operatorStatement:
                        date: '2026-01-15'
                        text: example
                        url: https://example.com/worldmonitor
                upstreamUnavailable: true
              schema:
                $ref: '#/components/schemas/ListPipelinesResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/get-pipeline-detail:
    get:
      tags:
        - SupplyChainService
      summary: GetPipelineDetail
      description: |-
        GetPipelineDetail returns a single pipeline with full evidence bundle
         + auto-revision-log entries. Loaded lazily on drawer open.
      operationId: GetPipelineDetail
      parameters:
        - name: pipelineId
          in: query
          description: Pipeline identifier to load with full evidence details.
          required: true
          example: transmed-pipeline
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                fetchedAt: '2026-01-15T12:00:00Z'
                pipeline:
                  capacityBcmYr: 1.5
                  capacityMbd: 1.5
                  commodityType: oil
                  endPoint:
                    lat: 40.7128
                    lon: -74.006
                  evidence:
                    classifierConfidence: 0.82
                    classifierVersion: example
                    commercialState: example
                    lastEvidenceUpdate: '2026-01-15'
                    operatorStatement:
                      date: '2026-01-15'
                      text: example
                      url: https://example.com/worldmonitor
                revisions:
                  - classifierVersion: example
                    date: '2026-01-15'
                    fieldChanged: example
                    newValue: example
                    previousValue: example
                unavailable: true
              schema:
                $ref: '#/components/schemas/GetPipelineDetailResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/list-storage-facilities:
    get:
      tags:
        - SupplyChainService
      summary: ListStorageFacilities
      description: |-
        ListStorageFacilities returns the curated strategic storage registry
         (UGS + SPR + LNG + crude tank farms) for the Energy Atlas DeckGL
         ScatterplotLayer. Public badges are DERIVED from evidence bundles
         server-side and versioned (classifier_version). Free-tier; see
         docs/methodology/storage.mdx.
      operationId: ListStorageFacilities
      parameters:
        - name: facilityType
          in: query
          description: |-
            Filter to one facility type. Accepts:
               "ugs" | "spr" | "lng_export" | "lng_import" | "crude_tank_farm"
             Omit (or pass empty) to receive all types.
          required: false
          example: ugs
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                classifierVersion: example
                facilities:
                  - capacityMb: 1.5
                    capacityMtpa: 1.5
                    capacityTwh: 1.5
                    country: US
                    evidence:
                      classifierConfidence: 0.82
                      classifierVersion: example
                      commercialState: example
                      fillDisclosed: true
                      fillSource: example
                fetchedAt: '2026-01-15T12:00:00Z'
                upstreamUnavailable: true
              schema:
                $ref: '#/components/schemas/ListStorageFacilitiesResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/get-storage-facility-detail:
    get:
      tags:
        - SupplyChainService
      summary: GetStorageFacilityDetail
      description: |-
        GetStorageFacilityDetail returns a single facility with full evidence
         bundle + revision log. Loaded lazily on drawer open.
      operationId: GetStorageFacilityDetail
      parameters:
        - name: facilityId
          in: query
          description: Storage facility identifier to load with full evidence details.
          required: true
          example: rough-storage
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                facility:
                  capacityMb: 1.5
                  capacityMtpa: 1.5
                  capacityTwh: 1.5
                  country: US
                  evidence:
                    classifierConfidence: 0.82
                    classifierVersion: example
                    commercialState: example
                    fillDisclosed: true
                    fillSource: example
                fetchedAt: '2026-01-15T12:00:00Z'
                revisions:
                  - classifierVersion: example
                    date: '2026-01-15'
                    fieldChanged: example
                    newValue: example
                    previousValue: example
                unavailable: true
              schema:
                $ref: '#/components/schemas/GetStorageFacilityDetailResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/list-fuel-shortages:
    get:
      tags:
        - SupplyChainService
      summary: ListFuelShortages
      description: |-
        ListFuelShortages returns the global fuel-shortage alert registry.
         Curated-only: severity ("confirmed" | "watch") is a row field authored
         at curation time, not a client-side derivation. Free tier.
      operationId: ListFuelShortages
      parameters:
        - name: country
          in: query
          description: Filter to one ISO 3166-1 alpha-2 country. Omit for global.
          required: false
          example: US
          schema:
            type: string
        - name: product
          in: query
          description: >-
            Filter to one product. Accepts: "petrol" | "diesel" | "jet" |
            "heating_oil".
             Omit for all products.
          required: false
          example: diesel
          schema:
            type: string
        - name: severity
          in: query
          description: >-
            Filter to one severity. Accepts: "confirmed" | "watch". Omit for
            both.
          required: false
          example: watch
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                classifierVersion: example
                fetchedAt: '2026-01-15T12:00:00Z'
                shortages:
                  - causeChain:
                      - example
                    country: US
                    evidence:
                      classifierConfidence: 0.82
                      classifierVersion: example
                      evidenceSources:
                        - authority: example
                          date: '2026-01-15'
                          sourceType: all
                          title: example
                          url: https://example.com/worldmonitor
                      firstRegulatorConfirmation: '40.7128'
                      lastEvidenceUpdate: '2026-01-15'
                    firstSeen: example
                    id: example-id
                upstreamUnavailable: true
              schema:
                $ref: '#/components/schemas/ListFuelShortagesResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/get-fuel-shortage-detail:
    get:
      tags:
        - SupplyChainService
      summary: GetFuelShortageDetail
      description: |-
        GetFuelShortageDetail returns a single shortage with full evidence
         bundle and citation timeline. Loaded lazily on drawer open.
      operationId: GetFuelShortageDetail
      parameters:
        - name: shortageId
          in: query
          description: Fuel-shortage identifier to load with full evidence details.
          required: true
          example: example-id
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                fetchedAt: '2026-01-15T12:00:00Z'
                shortage:
                  causeChain:
                    - example
                  country: US
                  evidence:
                    classifierConfidence: 0.82
                    classifierVersion: example
                    evidenceSources:
                      - authority: example
                        date: '2026-01-15'
                        sourceType: all
                        title: example
                        url: https://example.com/worldmonitor
                    firstRegulatorConfirmation: '40.7128'
                    lastEvidenceUpdate: '2026-01-15'
                  firstSeen: example
                  id: example-id
                unavailable: true
              schema:
                $ref: '#/components/schemas/GetFuelShortageDetailResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/list-energy-disruptions:
    get:
      tags:
        - SupplyChainService
      summary: ListEnergyDisruptions
      description: |-
        ListEnergyDisruptions returns the disruption event log for pipelines
         and storage facilities. Supports per-asset or per-asset-type filtering
         so panel drawers can fetch a scoped timeline without pulling the
         full registry.
      operationId: ListEnergyDisruptions
      parameters:
        - name: assetId
          in: query
          description: |-
            Filter to one asset. Omit for all. When set, also narrows to the
             matching asset_type if provided.
          required: false
          example: asset-example-1
          schema:
            type: string
        - name: assetType
          in: query
          description: 'Filter to one asset type. Accepts: "pipeline" | "storage".'
          required: false
          example: pipeline
          schema:
            type: string
        - name: ongoingOnly
          in: query
          description: If true, only return events with endAt empty (still ongoing).
          required: false
          example: true
          schema:
            type: boolean
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                classifierVersion: example
                events:
                  - assetId: asset-example-1
                    assetType: pipeline
                    capacityOfflineBcmYr: 1.5
                    capacityOfflineMbd: 1.5
                    causeChain:
                      - example
                fetchedAt: '2026-01-15T12:00:00Z'
                upstreamUnavailable: true
              schema:
                $ref: '#/components/schemas/ListEnergyDisruptionsResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/supply-chain/v1/get-china-corridor-control-towers:
    get:
      tags:
        - SupplyChainService
      summary: GetChinaCorridorControlTowers
      description: >-
        GetChinaCorridorControlTowers composes reviewed China logistics
        corridors
         from existing source caches. Conditions retain canonical provenance and
         explicit unavailable states; the response never emits a single risk score.
      operationId: GetChinaCorridorControlTowers
      parameters:
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                generatedAt: '2026-07-25T12:00:00.000Z'
                payloadJson: >-
                  {"generatedAt":"2026-07-25T12:00:00.000Z","corridors":[{"id":"china-yangtze-river-delta","name":"Yangtze
                  River Delta","description":"Reviewed coastal logistics
                  corridor joining Shanghai, Jiangsu, and Zhejiang
                  gateways.","boundary":[{"lat":28.4,"lon":118.2},{"lat":28.4,"lon":123.2},{"lat":33.4,"lon":123.2},{"lat":33.4,"lon":118.2},{"lat":28.4,"lon":118.2}],"nodes":[{"id":"china-node:yrd-port-shanghai","name":"Shanghai","type":"port","lat":31.1918,"lon":121.6442,"sourceOwner":"IMF
                  PortWatch","sourceSelector":{"family":"port","id":"port1188"}}],"availability":"partial","conditions":[{"family":"port","providerId":"portwatch","availability":"available","reason":null,"sourceSignals":[{"id":"signal:portwatch:port1188:2026-07-25T11:00:00.000Z","family":"port","selectorId":"port1188","availability":"available","publisher":{"id":"publisher:imf-portwatch","name":"IMF
                  PortWatch","type":"official"},"sourceUrl":"https://portwatch.imf.org/","sourceScope":"node","observationTime":"2026-07-25T11:00:00.000Z","observationTimePrecision":"instant","releaseTime":null,"releaseTimePrecision":"unknown","retrievalTime":"2026-07-25T11:05:00.000Z","retrievalTimePrecision":"instant","revision":null,"transportFreshness":"fresh","contentFreshness":"current","summary":"PortWatch
                  activity observation available for
                  Shanghai.","metrics":{"tankerCalls30d":14}}],"provenance":{"contractVersion":"decision-signal-provenance/v1","signalId":"signal:corridor-condition:china-yangtze-river-delta:port:2026-07-25T11:00:00.000Z","familyId":"composed_corridor_condition","claims":{"publisher":{"status":"known","value":{"id":"publisher:worldmonitor-derived","name":"WorldMonitor
                  derived
                  output","type":"derived_output","registryReference":null}},"observation_time":{"status":"known","value":{"role":"observation","value":"2026-07-25T11:00:00.000Z","precision":"instant"}},"source_url":{"status":"not_applicable","reason":"The
                  corridor condition links source URLs through its input
                  signals."},"original_reference":{"status":"not_applicable","reason":"The
                  corridor condition is composed from multiple source
                  records."},"original_language":{"status":"not_applicable","reason":"The
                  deterministic composition has no original-language
                  text."},"translation":{"status":"not_applicable","reason":"The
                  deterministic composition has no translated source
                  text."},"effective_time":{"status":"known","value":{"role":"effective","value":"2026-07-25T11:00:00.000Z","precision":"instant"}},"publication_time":{"status":"not_applicable","reason":"The
                  computed condition is not a publisher
                  release."},"retrieval_time":{"status":"known","value":{"role":"retrieval","value":"2026-07-25T11:05:00.000Z","precision":"instant"}},"revision":{"status":"known","value":{"vintageId":"china-yangtze-river-delta:port:2026-07-25T11:00:00.000Z","sequence":1,"state":"original"}},"supersession":{"status":"known","value":{"state":"current"}},"extraction_confidence":{"status":"not_applicable","reason":"Each
                  input signal owns its extraction
                  confidence."},"classification_confidence":{"status":"known","value":{"score":1,"method":"exact-reviewed-selector/v1"}},"corroboration":{"status":"known","value":{"state":"single_source","sourceSignalIds":["signal:portwatch:port1188:2026-07-25T11:00:00.000Z"]}},"transport_freshness":{"status":"known","value":{"state":"fresh","assessedAt":"2026-07-25T12:00:00.000Z","lastSuccessAt":"2026-07-25T11:05:00.000Z"}},"content_freshness":{"status":"known","value":{"state":"current","assessedAt":"2026-07-25T12:00:00.000Z","contentAsOf":"2026-07-25T11:00:00.000Z"}},"derivation":{"status":"known","value":{"methodId":"worldmonitor:china-corridor-condition","methodVersion":"1","computedAt":"2026-07-25T12:00:00.000Z","inputSignalIds":["signal:portwatch:port1188:2026-07-25T11:00:00.000Z"]}}}}},{"family":"aviation","providerId":"provider:aviation","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null},{"family":"hazard","providerId":"provider:hazard","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null},{"family":"power_energy","providerId":"provider:power_energy","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null},{"family":"strategic_industry","providerId":"provider:strategic_industry","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null},{"family":"trade","providerId":"provider:trade","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null}]},{"id":"china-greater-bay-area","name":"Greater
                  Bay Area","description":"Reviewed Pearl River Delta corridor
                  connecting Guangdong, Hong Kong, and Macao-facing port,
                  airport, and industrial
                  gateways.","boundary":[{"lat":20.5,"lon":111.5},{"lat":20.5,"lon":115.8},{"lat":24.8,"lon":115.8},{"lat":24.8,"lon":111.5},{"lat":20.5,"lon":111.5}],"nodes":[{"id":"china-node:gba-port-shekou","name":"Shekou
                  Shenzhen","type":"port","lat":22.47,"lon":113.9,"sourceOwner":"IMF
                  PortWatch","sourceSelector":{"family":"port","id":"port1189"}}],"availability":"partial","conditions":[{"family":"port","providerId":"portwatch","availability":"available","reason":null,"sourceSignals":[{"id":"signal:portwatch:port1189:2026-07-25T11:00:00.000Z","family":"port","selectorId":"port1189","availability":"available","publisher":{"id":"publisher:imf-portwatch","name":"IMF
                  PortWatch","type":"official"},"sourceUrl":"https://portwatch.imf.org/","sourceScope":"node","observationTime":"2026-07-25T11:00:00.000Z","observationTimePrecision":"instant","releaseTime":null,"releaseTimePrecision":"unknown","retrievalTime":"2026-07-25T11:05:00.000Z","retrievalTimePrecision":"instant","revision":null,"transportFreshness":"fresh","contentFreshness":"current","summary":"PortWatch
                  activity observation available for Shekou
                  Shenzhen.","metrics":{"tankerCalls30d":14}}],"provenance":{"contractVersion":"decision-signal-provenance/v1","signalId":"signal:corridor-condition:china-greater-bay-area:port:2026-07-25T11:00:00.000Z","familyId":"composed_corridor_condition","claims":{"publisher":{"status":"known","value":{"id":"publisher:worldmonitor-derived","name":"WorldMonitor
                  derived
                  output","type":"derived_output","registryReference":null}},"observation_time":{"status":"known","value":{"role":"observation","value":"2026-07-25T11:00:00.000Z","precision":"instant"}},"source_url":{"status":"not_applicable","reason":"The
                  corridor condition links source URLs through its input
                  signals."},"original_reference":{"status":"not_applicable","reason":"The
                  corridor condition is composed from multiple source
                  records."},"original_language":{"status":"not_applicable","reason":"The
                  deterministic composition has no original-language
                  text."},"translation":{"status":"not_applicable","reason":"The
                  deterministic composition has no translated source
                  text."},"effective_time":{"status":"known","value":{"role":"effective","value":"2026-07-25T11:00:00.000Z","precision":"instant"}},"publication_time":{"status":"not_applicable","reason":"The
                  computed condition is not a publisher
                  release."},"retrieval_time":{"status":"known","value":{"role":"retrieval","value":"2026-07-25T11:05:00.000Z","precision":"instant"}},"revision":{"status":"known","value":{"vintageId":"china-greater-bay-area:port:2026-07-25T11:00:00.000Z","sequence":1,"state":"original"}},"supersession":{"status":"known","value":{"state":"current"}},"extraction_confidence":{"status":"not_applicable","reason":"Each
                  input signal owns its extraction
                  confidence."},"classification_confidence":{"status":"known","value":{"score":1,"method":"exact-reviewed-selector/v1"}},"corroboration":{"status":"known","value":{"state":"single_source","sourceSignalIds":["signal:portwatch:port1189:2026-07-25T11:00:00.000Z"]}},"transport_freshness":{"status":"known","value":{"state":"fresh","assessedAt":"2026-07-25T12:00:00.000Z","lastSuccessAt":"2026-07-25T11:05:00.000Z"}},"content_freshness":{"status":"known","value":{"state":"current","assessedAt":"2026-07-25T12:00:00.000Z","contentAsOf":"2026-07-25T11:00:00.000Z"}},"derivation":{"status":"known","value":{"methodId":"worldmonitor:china-corridor-condition","methodVersion":"1","computedAt":"2026-07-25T12:00:00.000Z","inputSignalIds":["signal:portwatch:port1189:2026-07-25T11:00:00.000Z"]}}}}},{"family":"aviation","providerId":"provider:aviation","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null},{"family":"hazard","providerId":"provider:hazard","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null},{"family":"power_energy","providerId":"provider:power_energy","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null},{"family":"strategic_industry","providerId":"provider:strategic_industry","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null},{"family":"trade","providerId":"provider:trade","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null}]},{"id":"china-bohai-rim","name":"Bohai
                  Rim","description":"Reviewed northern maritime-industrial
                  corridor spanning Beijing-Tianjin, Hebei, Shandong, Liaoning,
                  and their major
                  gateways.","boundary":[{"lat":35.5,"lon":116},{"lat":35.5,"lon":123.5},{"lat":42.2,"lon":123.5},{"lat":42.2,"lon":116},{"lat":35.5,"lon":116}],"nodes":[{"id":"china-node:bohai-port-qingdao","name":"Qingdao","type":"port","lat":36.07,"lon":120.32,"sourceOwner":"IMF
                  PortWatch","sourceSelector":{"family":"port","id":"port1069"}}],"availability":"partial","conditions":[{"family":"port","providerId":"portwatch","availability":"available","reason":null,"sourceSignals":[{"id":"signal:portwatch:port1069:2026-07-25T11:00:00.000Z","family":"port","selectorId":"port1069","availability":"available","publisher":{"id":"publisher:imf-portwatch","name":"IMF
                  PortWatch","type":"official"},"sourceUrl":"https://portwatch.imf.org/","sourceScope":"node","observationTime":"2026-07-25T11:00:00.000Z","observationTimePrecision":"instant","releaseTime":null,"releaseTimePrecision":"unknown","retrievalTime":"2026-07-25T11:05:00.000Z","retrievalTimePrecision":"instant","revision":null,"transportFreshness":"fresh","contentFreshness":"current","summary":"PortWatch
                  activity observation available for
                  Qingdao.","metrics":{"tankerCalls30d":14}}],"provenance":{"contractVersion":"decision-signal-provenance/v1","signalId":"signal:corridor-condition:china-bohai-rim:port:2026-07-25T11:00:00.000Z","familyId":"composed_corridor_condition","claims":{"publisher":{"status":"known","value":{"id":"publisher:worldmonitor-derived","name":"WorldMonitor
                  derived
                  output","type":"derived_output","registryReference":null}},"observation_time":{"status":"known","value":{"role":"observation","value":"2026-07-25T11:00:00.000Z","precision":"instant"}},"source_url":{"status":"not_applicable","reason":"The
                  corridor condition links source URLs through its input
                  signals."},"original_reference":{"status":"not_applicable","reason":"The
                  corridor condition is composed from multiple source
                  records."},"original_language":{"status":"not_applicable","reason":"The
                  deterministic composition has no original-language
                  text."},"translation":{"status":"not_applicable","reason":"The
                  deterministic composition has no translated source
                  text."},"effective_time":{"status":"known","value":{"role":"effective","value":"2026-07-25T11:00:00.000Z","precision":"instant"}},"publication_time":{"status":"not_applicable","reason":"The
                  computed condition is not a publisher
                  release."},"retrieval_time":{"status":"known","value":{"role":"retrieval","value":"2026-07-25T11:05:00.000Z","precision":"instant"}},"revision":{"status":"known","value":{"vintageId":"china-bohai-rim:port:2026-07-25T11:00:00.000Z","sequence":1,"state":"original"}},"supersession":{"status":"known","value":{"state":"current"}},"extraction_confidence":{"status":"not_applicable","reason":"Each
                  input signal owns its extraction
                  confidence."},"classification_confidence":{"status":"known","value":{"score":1,"method":"exact-reviewed-selector/v1"}},"corroboration":{"status":"known","value":{"state":"single_source","sourceSignalIds":["signal:portwatch:port1069:2026-07-25T11:00:00.000Z"]}},"transport_freshness":{"status":"known","value":{"state":"fresh","assessedAt":"2026-07-25T12:00:00.000Z","lastSuccessAt":"2026-07-25T11:05:00.000Z"}},"content_freshness":{"status":"known","value":{"state":"current","assessedAt":"2026-07-25T12:00:00.000Z","contentAsOf":"2026-07-25T11:00:00.000Z"}},"derivation":{"status":"known","value":{"methodId":"worldmonitor:china-corridor-condition","methodVersion":"1","computedAt":"2026-07-25T12:00:00.000Z","inputSignalIds":["signal:portwatch:port1069:2026-07-25T11:00:00.000Z"]}}}}},{"family":"aviation","providerId":"provider:aviation","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null},{"family":"hazard","providerId":"provider:hazard","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null},{"family":"power_energy","providerId":"provider:power_energy","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null},{"family":"strategic_industry","providerId":"provider:strategic_industry","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null},{"family":"trade","providerId":"provider:trade","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null}]},{"id":"china-western-land-sea-corridor","name":"Western
                  Land-Sea Corridor","description":"Reviewed western corridor
                  linking inland manufacturing hubs, Xinjiang land crossings,
                  and Guangxi gateways to regional and maritime
                  routes.","boundary":[{"lat":20.4,"lon":106.2},{"lat":20.4,"lon":110.4},{"lat":32.5,"lon":110.4},{"lat":47,"lon":91},{"lat":47,"lon":78.5},{"lat":41,"lon":78.5},{"lat":27,"lon":99.7},{"lat":22,"lon":105.8},{"lat":20.4,"lon":106.2}],"nodes":[{"id":"china-node:western-port-qinzhou","name":"Qinzhou","type":"port","lat":21.6788,"lon":108.6383,"sourceOwner":"IMF
                  PortWatch","sourceSelector":{"family":"port","id":"port1071"}}],"availability":"partial","conditions":[{"family":"port","providerId":"portwatch","availability":"available","reason":null,"sourceSignals":[{"id":"signal:portwatch:port1071:2026-07-25T11:00:00.000Z","family":"port","selectorId":"port1071","availability":"available","publisher":{"id":"publisher:imf-portwatch","name":"IMF
                  PortWatch","type":"official"},"sourceUrl":"https://portwatch.imf.org/","sourceScope":"node","observationTime":"2026-07-25T11:00:00.000Z","observationTimePrecision":"instant","releaseTime":null,"releaseTimePrecision":"unknown","retrievalTime":"2026-07-25T11:05:00.000Z","retrievalTimePrecision":"instant","revision":null,"transportFreshness":"fresh","contentFreshness":"current","summary":"PortWatch
                  activity observation available for
                  Qinzhou.","metrics":{"tankerCalls30d":14}}],"provenance":{"contractVersion":"decision-signal-provenance/v1","signalId":"signal:corridor-condition:china-western-land-sea-corridor:port:2026-07-25T11:00:00.000Z","familyId":"composed_corridor_condition","claims":{"publisher":{"status":"known","value":{"id":"publisher:worldmonitor-derived","name":"WorldMonitor
                  derived
                  output","type":"derived_output","registryReference":null}},"observation_time":{"status":"known","value":{"role":"observation","value":"2026-07-25T11:00:00.000Z","precision":"instant"}},"source_url":{"status":"not_applicable","reason":"The
                  corridor condition links source URLs through its input
                  signals."},"original_reference":{"status":"not_applicable","reason":"The
                  corridor condition is composed from multiple source
                  records."},"original_language":{"status":"not_applicable","reason":"The
                  deterministic composition has no original-language
                  text."},"translation":{"status":"not_applicable","reason":"The
                  deterministic composition has no translated source
                  text."},"effective_time":{"status":"known","value":{"role":"effective","value":"2026-07-25T11:00:00.000Z","precision":"instant"}},"publication_time":{"status":"not_applicable","reason":"The
                  computed condition is not a publisher
                  release."},"retrieval_time":{"status":"known","value":{"role":"retrieval","value":"2026-07-25T11:05:00.000Z","precision":"instant"}},"revision":{"status":"known","value":{"vintageId":"china-western-land-sea-corridor:port:2026-07-25T11:00:00.000Z","sequence":1,"state":"original"}},"supersession":{"status":"known","value":{"state":"current"}},"extraction_confidence":{"status":"not_applicable","reason":"Each
                  input signal owns its extraction
                  confidence."},"classification_confidence":{"status":"known","value":{"score":1,"method":"exact-reviewed-selector/v1"}},"corroboration":{"status":"known","value":{"state":"single_source","sourceSignalIds":["signal:portwatch:port1071:2026-07-25T11:00:00.000Z"]}},"transport_freshness":{"status":"known","value":{"state":"fresh","assessedAt":"2026-07-25T12:00:00.000Z","lastSuccessAt":"2026-07-25T11:05:00.000Z"}},"content_freshness":{"status":"known","value":{"state":"current","assessedAt":"2026-07-25T12:00:00.000Z","contentAsOf":"2026-07-25T11:00:00.000Z"}},"derivation":{"status":"known","value":{"methodId":"worldmonitor:china-corridor-condition","methodVersion":"1","computedAt":"2026-07-25T12:00:00.000Z","inputSignalIds":["signal:portwatch:port1071:2026-07-25T11:00:00.000Z"]}}}}},{"family":"aviation","providerId":"provider:aviation","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null},{"family":"hazard","providerId":"provider:hazard","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null},{"family":"power_energy","providerId":"provider:power_energy","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null},{"family":"strategic_industry","providerId":"provider:strategic_industry","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null},{"family":"trade","providerId":"provider:trade","availability":"unavailable","reason":"No
                  reviewed source observation is available in this
                  example.","sourceSignals":[],"provenance":null}]}]}
                upstreamUnavailable: false
              schema:
                $ref: '#/components/schemas/GetChinaCorridorControlTowersResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
components:
  securitySchemes:
    WorldMonitorKey:
      type: apiKey
      in: header
      name: X-WorldMonitor-Key
      description: User-issued WorldMonitor API key.
    ApiKeyHeader:
      type: apiKey
      in: header
      name: X-Api-Key
      description: Alias header for the WorldMonitor API key (X-WorldMonitor-Key).
    BearerAuth:
      type: http
      scheme: bearer
      description: >-
        Bearer token: a Clerk-issued JWT for browser session flows, passed as
        Authorization: Bearer <token>.
  schemas:
    ChinaCorridorControlTowerResponse:
      type: object
      description: >-
        Canonical transparent China logistics corridor composition decoded from
        payloadJson.
      required:
        - generatedAt
        - corridors
      properties:
        generatedAt:
          type: string
          format: date-time
        corridors:
          type: array
          items:
            $ref: '#/components/schemas/ChinaCorridorControlTower'
    ChinaCorridorControlTower:
      type: object
      required:
        - id
        - name
        - description
        - boundary
        - nodes
        - availability
        - conditions
      properties:
        id:
          type: string
          enum:
            - china-yangtze-river-delta
            - china-greater-bay-area
            - china-bohai-rim
            - china-western-land-sea-corridor
        name:
          type: string
        description:
          type: string
        boundary:
          type: array
          items:
            type: object
            required:
              - lat
              - lon
            properties:
              lat:
                type: number
                format: double
              lon:
                type: number
                format: double
        nodes:
          type: array
          items:
            type: object
            required:
              - id
              - name
              - type
              - lat
              - lon
              - sourceOwner
            properties:
              id:
                type: string
              name:
                type: string
              type:
                type: string
                enum:
                  - port
                  - airport
                  - crossing
                  - industrial
              lat:
                type: number
                format: double
              lon:
                type: number
                format: double
              sourceOwner:
                type: string
              sourceSelector:
                type: object
                required:
                  - family
                  - id
                properties:
                  family:
                    type: string
                    enum:
                      - port
                      - aviation
                      - hazard
                      - power_energy
                      - strategic_industry
                      - trade
                  id:
                    type: string
        availability:
          type: string
          enum:
            - available
            - partial
            - stale
            - unavailable
        conditions:
          type: array
          items:
            $ref: '#/components/schemas/ChinaCorridorCondition'
    ChinaCorridorCondition:
      type: object
      required:
        - family
        - providerId
        - availability
        - reason
        - sourceSignals
        - provenance
      properties:
        family:
          type: string
          enum:
            - port
            - aviation
            - hazard
            - power_energy
            - strategic_industry
            - trade
        providerId:
          type: string
        availability:
          type: string
          enum:
            - available
            - partial
            - stale
            - unavailable
        reason:
          type:
            - string
            - 'null'
        sourceSignals:
          type: array
          items:
            type: object
            required:
              - id
              - family
              - selectorId
              - availability
              - publisher
              - sourceUrl
              - sourceScope
              - observationTime
              - observationTimePrecision
              - releaseTime
              - releaseTimePrecision
              - retrievalTime
              - retrievalTimePrecision
              - revision
              - transportFreshness
              - contentFreshness
              - summary
              - metrics
            properties:
              id:
                type: string
              family:
                type: string
                enum:
                  - port
                  - aviation
                  - hazard
                  - power_energy
                  - strategic_industry
                  - trade
              selectorId:
                type: string
              corridorIds:
                type: array
                items:
                  type: string
                  enum:
                    - china-yangtze-river-delta
                    - china-greater-bay-area
                    - china-bohai-rim
                    - china-western-land-sea-corridor
              availability:
                type: string
                enum:
                  - available
                  - stale
                  - unavailable
              publisher:
                type: object
                required:
                  - id
                  - name
                  - type
                properties:
                  id:
                    type: string
                  name:
                    type: string
                  type:
                    type: string
                    enum:
                      - official
                      - market
                      - independent
                      - derived
                      - unknown
              sourceUrl:
                type:
                  - string
                  - 'null'
                format: uri
              sourceScope:
                type: string
                enum:
                  - node
                  - regional
                  - national
              observationTime:
                type:
                  - string
                  - 'null'
              observationTimePrecision:
                type: string
                enum:
                  - instant
                  - day
                  - month
                  - year
                  - unknown
              releaseTime:
                type:
                  - string
                  - 'null'
              releaseTimePrecision:
                type: string
                enum:
                  - instant
                  - day
                  - month
                  - year
                  - unknown
              retrievalTime:
                type:
                  - string
                  - 'null'
              retrievalTimePrecision:
                type: string
                enum:
                  - instant
                  - day
                  - month
                  - year
                  - unknown
              revision:
                oneOf:
                  - type: object
                    required:
                      - vintageId
                      - sequence
                      - state
                    properties:
                      vintageId:
                        type: string
                      sequence:
                        type: number
                      state:
                        type: string
                        enum:
                          - original
                          - revised
                          - corrected
                  - type: 'null'
              transportFreshness:
                type: string
                enum:
                  - fresh
                  - stale
                  - missing
                  - error
              contentFreshness:
                type: string
                enum:
                  - current
                  - stale
                  - unavailable
                  - partial
                  - timestamp_unknown
              summary:
                type: string
              metrics:
                type: object
                additionalProperties:
                  type:
                    - string
                    - number
                    - boolean
                    - 'null'
        provenance:
          oneOf:
            - $ref: '#/components/schemas/ChinaCorridorProvenance'
            - type: 'null'
    ChinaCorridorProvenance:
      type: object
      description: >-
        The #5581 decision-signal provenance envelope retained for the composed
        condition.
      required:
        - contractVersion
        - signalId
        - familyId
        - claims
      properties:
        contractVersion:
          type: string
          const: decision-signal-provenance/v1
        signalId:
          type: string
        familyId:
          type: string
          const: composed_corridor_condition
        claims:
          type: object
          required:
            - publisher
            - source_url
            - original_reference
            - original_language
            - translation
            - observation_time
            - effective_time
            - publication_time
            - retrieval_time
            - revision
            - supersession
            - extraction_confidence
            - classification_confidence
            - corroboration
            - transport_freshness
            - content_freshness
            - derivation
          properties:
            publisher:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - status
                    - value
                  properties:
                    status:
                      type: string
                      const: known
                    value:
                      type: object
                      additionalProperties: false
                      required:
                        - id
                        - name
                        - type
                        - registryReference
                      properties:
                        id:
                          type: string
                        name:
                          type: string
                        type:
                          type: string
                          enum:
                            - official_government
                            - state_controlled_media
                            - official_exchange
                            - independent_observation
                            - independent_media
                            - wire_service
                            - market_publisher
                            - derived_output
                            - unknown
                        registryReference:
                          oneOf:
                            - type: object
                              additionalProperties: false
                              required:
                                - sourceName
                                - sourceType
                                - propagandaRisk
                              properties:
                                sourceName:
                                  type: string
                                sourceType:
                                  type: string
                                propagandaRisk:
                                  type: string
                            - type: 'null'
                - $ref: '#/components/schemas/ChinaCorridorProvenanceClaim'
            source_url:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - status
                    - value
                  properties:
                    status:
                      type: string
                      const: known
                    value:
                      type: string
                      format: uri
                - $ref: '#/components/schemas/ChinaCorridorProvenanceClaim'
            original_reference:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - status
                    - value
                  properties:
                    status:
                      type: string
                      const: known
                    value:
                      type: object
                      additionalProperties: false
                      required:
                        - kind
                        - id
                      properties:
                        kind:
                          type: string
                          enum:
                            - document
                            - text
                            - observation
                            - event
                            - dataset
                        id:
                          type: string
                        contentHash:
                          type: string
                - $ref: '#/components/schemas/ChinaCorridorProvenanceClaim'
            original_language:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - status
                    - value
                  properties:
                    status:
                      type: string
                      const: known
                    value:
                      type: string
                - $ref: '#/components/schemas/ChinaCorridorProvenanceClaim'
            translation:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - status
                    - value
                  properties:
                    status:
                      type: string
                      const: known
                    value:
                      type: object
                      additionalProperties: false
                      required:
                        - state
                      properties:
                        state:
                          type: string
                          enum:
                            - unavailable
                            - not_translated
                            - machine_assisted
                            - human_reviewed
                        targetLanguage:
                          type: string
                - $ref: '#/components/schemas/ChinaCorridorProvenanceClaim'
            observation_time:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - status
                    - value
                  properties:
                    status:
                      type: string
                      const: known
                    value:
                      type: object
                      additionalProperties: false
                      required:
                        - role
                        - value
                        - precision
                      properties:
                        role:
                          type: string
                          const: observation
                        value:
                          type: string
                        precision:
                          type: string
                          enum:
                            - instant
                            - day
                            - month
                            - year
                - $ref: '#/components/schemas/ChinaCorridorProvenanceClaim'
            effective_time:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - status
                    - value
                  properties:
                    status:
                      type: string
                      const: known
                    value:
                      type: object
                      additionalProperties: false
                      required:
                        - role
                        - value
                        - precision
                      properties:
                        role:
                          type: string
                          const: effective
                        value:
                          type: string
                        precision:
                          type: string
                          enum:
                            - instant
                            - day
                            - month
                            - year
                - $ref: '#/components/schemas/ChinaCorridorProvenanceClaim'
            publication_time:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - status
                    - value
                  properties:
                    status:
                      type: string
                      const: known
                    value:
                      type: object
                      additionalProperties: false
                      required:
                        - role
                        - value
                        - precision
                      properties:
                        role:
                          type: string
                          const: publication
                        value:
                          type: string
                        precision:
                          type: string
                          enum:
                            - instant
                            - day
                            - month
                            - year
                - $ref: '#/components/schemas/ChinaCorridorProvenanceClaim'
            retrieval_time:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - status
                    - value
                  properties:
                    status:
                      type: string
                      const: known
                    value:
                      type: object
                      additionalProperties: false
                      required:
                        - role
                        - value
                        - precision
                      properties:
                        role:
                          type: string
                          const: retrieval
                        value:
                          type: string
                        precision:
                          type: string
                          enum:
                            - instant
                            - day
                            - month
                            - year
                - $ref: '#/components/schemas/ChinaCorridorProvenanceClaim'
            revision:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - status
                    - value
                  properties:
                    status:
                      type: string
                      const: known
                    value:
                      type: object
                      additionalProperties: false
                      required:
                        - vintageId
                        - sequence
                        - state
                      properties:
                        vintageId:
                          type: string
                        sequence:
                          type: integer
                          minimum: 1
                        state:
                          type: string
                          enum:
                            - preliminary
                            - original
                            - revised
                            - corrected
                - $ref: '#/components/schemas/ChinaCorridorProvenanceClaim'
            supersession:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - status
                    - value
                  properties:
                    status:
                      type: string
                      const: known
                    value:
                      type: object
                      additionalProperties: false
                      required:
                        - state
                      properties:
                        state:
                          type: string
                          enum:
                            - current
                            - corrected
                            - cancelled
                            - superseded
                        relatedSignalId:
                          type: string
                        reason:
                          type: string
                - $ref: '#/components/schemas/ChinaCorridorProvenanceClaim'
            extraction_confidence:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - status
                    - value
                  properties:
                    status:
                      type: string
                      const: known
                    value:
                      type: object
                      additionalProperties: false
                      required:
                        - score
                        - method
                      properties:
                        score:
                          type: number
                          minimum: 0
                          maximum: 1
                        method:
                          type: string
                - $ref: '#/components/schemas/ChinaCorridorProvenanceClaim'
            classification_confidence:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - status
                    - value
                  properties:
                    status:
                      type: string
                      const: known
                    value:
                      type: object
                      additionalProperties: false
                      required:
                        - score
                        - method
                      properties:
                        score:
                          type: number
                          minimum: 0
                          maximum: 1
                        method:
                          type: string
                - $ref: '#/components/schemas/ChinaCorridorProvenanceClaim'
            corroboration:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - status
                    - value
                  properties:
                    status:
                      type: string
                      const: known
                    value:
                      type: object
                      additionalProperties: false
                      required:
                        - state
                        - sourceSignalIds
                      properties:
                        state:
                          type: string
                          enum:
                            - single_source
                            - multi_source
                            - independently_corroborated
                            - contradicted
                        sourceSignalIds:
                          type: array
                          items:
                            type: string
                - $ref: '#/components/schemas/ChinaCorridorProvenanceClaim'
            transport_freshness:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - status
                    - value
                  properties:
                    status:
                      type: string
                      const: known
                    value:
                      type: object
                      additionalProperties: false
                      required:
                        - state
                        - assessedAt
                      properties:
                        state:
                          type: string
                          enum:
                            - fresh
                            - stale
                            - missing
                            - error
                        assessedAt:
                          type: string
                          format: date-time
                        lastSuccessAt:
                          type: string
                          format: date-time
                - $ref: '#/components/schemas/ChinaCorridorProvenanceClaim'
            content_freshness:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - status
                    - value
                  properties:
                    status:
                      type: string
                      const: known
                    value:
                      type: object
                      additionalProperties: false
                      required:
                        - state
                        - assessedAt
                      properties:
                        state:
                          type: string
                          enum:
                            - current
                            - stale
                            - unavailable
                            - partial
                            - timestamp_unknown
                        assessedAt:
                          type: string
                          format: date-time
                        contentAsOf:
                          type: string
                - $ref: '#/components/schemas/ChinaCorridorProvenanceClaim'
            derivation:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - status
                    - value
                  properties:
                    status:
                      type: string
                      const: known
                    value:
                      type: object
                      additionalProperties: false
                      required:
                        - methodId
                        - methodVersion
                        - computedAt
                        - inputSignalIds
                      properties:
                        methodId:
                          type: string
                        methodVersion:
                          type: string
                        computedAt:
                          type: string
                          format: date-time
                        inputSignalIds:
                          type: array
                          items:
                            type: string
                - $ref: '#/components/schemas/ChinaCorridorProvenanceClaim'
    ChinaCorridorProvenanceClaim:
      type: object
      additionalProperties: false
      required:
        - status
        - reason
      properties:
        status:
          type: string
          enum:
            - unknown
            - not_applicable
        reason:
          type: string
    JmespathProjectionError:
      description: >-
        Returned when a REST jmespath projection is invalid or exceeds the
        expression/output byte limits.
      properties:
        _jmespath_error:
          description: Projection error discriminator and details.
          type: string
        original_keys:
          description: Top-level keys or shape of the unprojected response.
          items:
            type: string
          type: array
      required:
        - _jmespath_error
        - original_keys
      type: object
    UnauthorizedError:
      type: object
      properties:
        error:
          type: string
          description: Human-readable error message.
      required:
        - error
      description: >-
        Returned when the API key is missing, malformed, or lacks current API
        access.
    Error:
      type: object
      properties:
        message:
          type: string
          description: Error message (e.g., 'user not found', 'database connection failed')
      description: >-
        Error is returned when a handler encounters an error. It contains a
        simple error message that the developer can customize.
    InvalidRequestBodyError:
      type: object
      description: Returned when a JSON POST request body is empty or malformed.
      properties:
        message:
          type: string
          description: Invalid request body
      required:
        - message
    GatewayError:
      type: object
      description: >-
        Returned by gateway infrastructure errors before an RPC handler runs,
        such as origin, routing, method, authentication, or quota checks.
      properties:
        error:
          oneOf:
            - type: string
            - type: object
              additionalProperties: true
          description: Gateway error reason or structured gateway failure details.
      required:
        - error
    RateLimitError:
      type: object
      description: Returned when a gateway or handler rate limit rejects the request.
      properties:
        error:
          type: string
          description: Human-readable rate-limit failure reason.
      required:
        - error
    ForbiddenError:
      type: object
      properties:
        error:
          type: string
          description: Human-readable entitlement failure reason.
        requiredTier:
          type: integer
          format: int32
          description: Minimum entitlement tier required for this endpoint.
        currentTier:
          type: integer
          format: int32
          description: Caller entitlement tier when known.
        planKey:
          type: string
          description: Caller plan key when known.
      required:
        - error
      description: >-
        Returned when a PRO-gated endpoint denies access because the caller has
        no resolved authenticated user, entitlements cannot be verified, or the
        caller lacks the required entitlement tier.
    FieldViolation:
      type: object
      properties:
        field:
          type: string
          description: >-
            The field path that failed validation (e.g., 'user.email' for nested
            fields). For header validation, this will be the header name (e.g.,
            'X-API-Key')
        description:
          type: string
          description: >-
            Human-readable description of the validation violation (e.g., 'must
            be a valid email address', 'required field missing')
      required:
        - field
        - description
      description: FieldViolation describes a single validation error for a specific field.
    ValidationError:
      type: object
      properties:
        violations:
          type: array
          items:
            $ref: '#/components/schemas/FieldViolation'
          description: List of validation violations
      required:
        - violations
      description: >-
        ValidationError is returned when request validation fails. It contains a
        list of field violations describing what went wrong.
    GetShippingRatesRequest:
      type: object
    GetShippingRatesResponse:
      type: object
      properties:
        indices:
          type: array
          items:
            $ref: '#/components/schemas/ShippingIndex'
        fetchedAt:
          type: string
        upstreamUnavailable:
          type: boolean
    ShippingIndex:
      type: object
      properties:
        indexId:
          type: string
        name:
          type: string
        currentValue:
          type: number
          format: double
        previousValue:
          type: number
          format: double
        changePct:
          type: number
          format: double
        unit:
          type: string
        history:
          type: array
          items:
            $ref: '#/components/schemas/ShippingRatePoint'
        spikeAlert:
          type: boolean
    ShippingRatePoint:
      type: object
      properties:
        date:
          type: string
        value:
          type: number
          format: double
    GetChokepointStatusRequest:
      type: object
    GetChokepointStatusResponse:
      type: object
      properties:
        chokepoints:
          type: array
          items:
            $ref: '#/components/schemas/ChokepointInfo'
        fetchedAt:
          type: string
          description: |-
            ISO-8601 time the status snapshot was fetched. Empty string with
             upstream_unavailable=true means the snapshot is unavailable/degraded.
        upstreamUnavailable:
          type: boolean
          description: >-
            True when upstream seed/relay data is unavailable or partial. When
            true, an
             empty chokepoints array is graceful degradation, not confirmed zero data.
    ChokepointInfo:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        lat:
          type: number
          format: double
        lon:
          type: number
          format: double
        disruptionScore:
          type: integer
          format: int32
        status:
          type: string
          description: >-
            Traffic-light score badge: green (<20), yellow (20-49), or red
            (>=50).
             Not an operational closure taxonomy.
        activeWarnings:
          type: integer
          format: int32
        congestionLevel:
          type: string
        affectedRoutes:
          type: array
          items:
            type: string
        description:
          type: string
        aisDisruptions:
          type: integer
          format: int32
        directions:
          type: array
          items:
            type: string
        directionalDwt:
          type: array
          items:
            $ref: '#/components/schemas/DirectionalDwt'
        transitSummary:
          $ref: '#/components/schemas/TransitSummary'
        flowEstimate:
          $ref: '#/components/schemas/FlowEstimate'
        warRiskTier:
          type: string
          enum:
            - WAR_RISK_TIER_UNSPECIFIED
            - WAR_RISK_TIER_NORMAL
            - WAR_RISK_TIER_ELEVATED
            - WAR_RISK_TIER_HIGH
            - WAR_RISK_TIER_CRITICAL
            - WAR_RISK_TIER_WAR_ZONE
          description: |-
            *
             War risk tier derived from Lloyd's JWC Listed Areas + OSINT threat classification.
             This is a FREE field (no PRO gate) — it exposes the existing server-internal
             threatLevel from ChokepointConfig, making it available to clients for badges
             and bypass corridor scoring.
    DirectionalDwt:
      type: object
      properties:
        direction:
          type: string
        dwtThousandTonnes:
          type: number
          format: double
        wowChangePct:
          type: number
          format: double
    TransitSummary:
      type: object
      properties:
        todayTotal:
          type: integer
          format: int32
        todayTanker:
          type: integer
          format: int32
        todayCargo:
          type: integer
          format: int32
        todayOther:
          type: integer
          format: int32
        wowChangePct:
          type: number
          format: double
        history:
          type: array
          items:
            $ref: '#/components/schemas/TransitDayCount'
        riskLevel:
          type: string
        incidentCount7d:
          type: integer
          format: int32
        disruptionPct:
          type: number
          format: double
        riskSummary:
          type: string
        riskReportAction:
          type: string
        dataAvailable:
          type: boolean
          description: >-
            False when the upstream portwatch/relay source did not return data
            for
             this chokepoint in the current cycle — the summary fields are zero-state
             fill, not a genuine "zero traffic" reading. Client should render a
             "transit data unavailable" indicator and skip stat/chart rendering.
    TransitDayCount:
      type: object
      properties:
        date:
          type: string
        tanker:
          type: integer
          format: int32
        cargo:
          type: integer
          format: int32
        other:
          type: integer
          format: int32
        total:
          type: integer
          format: int32
        container:
          type: integer
          format: int32
        dryBulk:
          type: integer
          format: int32
        generalCargo:
          type: integer
          format: int32
        roro:
          type: integer
          format: int32
        capContainer:
          type: number
          format: double
        capDryBulk:
          type: number
          format: double
        capGeneralCargo:
          type: number
          format: double
        capRoro:
          type: number
          format: double
        capTanker:
          type: number
          format: double
    FlowEstimate:
      type: object
      properties:
        currentMbd:
          type: number
          format: double
          description: |-
            Current estimated flow in million barrels/day. Computed as
             baseline_mbd * flow_ratio.
        baselineMbd:
          type: number
          format: double
          description: >-
            EIA 2023 annual reference level in million barrels/day for the
            mapped
             seven-item live-flow subset.
        flowRatio:
          type: number
          format: double
          description: >-
            Latest 7-day PortWatch average divided by the preceding rolling
            baseline
             window of up to 90 days, clamped to 0.0-1.5.
        disrupted:
          type: boolean
          description: |-
            True when each of the latest 3 daily ratios is below 85% of the same
             rolling baseline window. Separate from the green/yellow/red status badge.
        source:
          type: string
          description: |-
            Flow source: "portwatch-dwt" when DWT-majority coverage is used,
             otherwise "portwatch-counts" for vessel-count coverage.
        hazardAlertLevel:
          type: string
          description: >-
            Nearest active GDACS hazard alert level within the configured
            radius:
             "RED", "ORANGE", or empty string when no nearby alert applies.
        hazardAlertName:
          type: string
          description: |-
            Name of the nearest active GDACS hazard event within the configured
             radius, or empty string when no nearby alert applies.
    GetChokepointHistoryRequest:
      type: object
      properties:
        chokepointId:
          type: string
          description: Chokepoint identifier whose transit history should be returned.
      required:
        - chokepointId
      description: |-
        GetChokepointHistory returns the transit-count history for a single
         chokepoint. Loaded lazily on card expand so the main chokepoint-status
         response can stay compact (no 180-day history per chokepoint).
    GetChokepointHistoryResponse:
      type: object
      properties:
        chokepointId:
          type: string
        history:
          type: array
          items:
            $ref: '#/components/schemas/TransitDayCount'
        fetchedAt:
          type: string
          format: int64
    GetCriticalMineralsRequest:
      type: object
    GetCriticalMineralsResponse:
      type: object
      properties:
        minerals:
          type: array
          items:
            $ref: '#/components/schemas/CriticalMineral'
        fetchedAt:
          type: string
        upstreamUnavailable:
          type: boolean
    CriticalMineral:
      type: object
      properties:
        mineral:
          type: string
        topProducers:
          type: array
          items:
            $ref: '#/components/schemas/MineralProducer'
        hhi:
          type: number
          format: double
        riskRating:
          type: string
        globalProduction:
          type: number
          format: double
        unit:
          type: string
    MineralProducer:
      type: object
      properties:
        country:
          type: string
        countryCode:
          type: string
        productionTonnes:
          type: number
          format: double
        sharePct:
          type: number
          format: double
    GetShippingStressRequest:
      type: object
    GetShippingStressResponse:
      type: object
      properties:
        carriers:
          type: array
          items:
            $ref: '#/components/schemas/ShippingStressCarrier'
        stressScore:
          type: number
          format: double
          description: Composite stress score 0–100 (higher = more disruption).
        stressLevel:
          type: string
          description: '"low" | "moderate" | "elevated" | "critical".'
        fetchedAt:
          type: integer
          format: int64
          description: 'Warning: Values > 2^53 may lose precision in JavaScript'
        upstreamUnavailable:
          type: boolean
          description: >-
            Set to true when upstream data source is unavailable and cached data
            is stale.
    ShippingStressCarrier:
      type: object
      properties:
        symbol:
          type: string
          description: Ticker or identifier (e.g., "BDRY", "ZIM").
        name:
          type: string
          description: Human-readable name.
        price:
          type: number
          format: double
          description: Current price.
        changePct:
          type: number
          format: double
          description: Percentage change from previous close.
        carrierType:
          type: string
          description: 'Carrier type: "etf" | "carrier" | "index".'
        sparkline:
          type: array
          items:
            type: number
            format: double
            description: 30-day price sparkline.
      description: >-
        ShippingStressCarrier represents market stress data for a carrier or
        shipping index.
    GetCountryChokepointIndexRequest:
      type: object
      properties:
        iso2:
          type: string
          pattern: ^[A-Z]{2}$
          description: ISO 3166-1 alpha-2 country code (uppercase).
        hs2:
          type: string
          description: >-
            HS2 chapter (2-digit string). Defaults to "27" (energy/mineral
            fuels) when absent.
      required:
        - iso2
      description: >-
        GetCountryChokepointIndexRequest specifies the country and optional HS2
        chapter.
    GetCountryChokepointIndexResponse:
      type: object
      properties:
        iso2:
          type: string
          description: ISO 3166-1 alpha-2 country code echoed from the request.
        hs2:
          type: string
          description: HS2 chapter used for the computation.
        exposures:
          type: array
          items:
            $ref: '#/components/schemas/ChokepointExposureEntry'
        primaryChokepointId:
          type: string
          description: Canonical ID of the chokepoint with the highest exposure score.
        vulnerabilityIndex:
          type: number
          format: double
          description: >-
            Composite vulnerability index 0-100: top1 * 0.5 + top2 * 0.3 + top3
            * 0.2.
        fetchedAt:
          type: string
          description: ISO timestamp of when this data was last seeded.
      description: >-
        GetCountryChokepointIndexResponse returns exposure scores for all
        relevant chokepoints.
    ChokepointExposureEntry:
      type: object
      properties:
        chokepointId:
          type: string
          description: Canonical chokepoint ID from the chokepoint registry.
        chokepointName:
          type: string
          description: Human-readable chokepoint name.
        exposureScore:
          type: number
          format: double
          description: >-
            Exposure score 0-100; higher = more dependent on this chokepoint.
            With
             bilateral product data, sums routeCoverage * exporterShare * productWeight
             * 100 across matching products; fallback uses route overlap only. HS2 27
             supported energy chokepoints receive a 1.5x boost capped at 100.
        coastSide:
          type: string
          description: >-
            Which ocean/basin side the country's ports face (atlantic, pacific,
            indian, med, multi, landlocked).
        shockSupported:
          type: boolean
          description: >-
            Whether the shock model is supported for this chokepoint + hs2
            combination.
      description: >-
        ChokepointExposureEntry holds per-chokepoint exposure data for a
        country.
    GetBypassOptionsRequest:
      type: object
      properties:
        chokepointId:
          type: string
          description: Chokepoint identifier to evaluate for bypass options.
        cargoType:
          type: string
          description: 'container | tanker | bulk | roro  (default: "container")'
        closurePct:
          type: integer
          format: int32
          description: '0-100, percent of capacity blocked (default: 100)'
      required:
        - chokepointId
    GetBypassOptionsResponse:
      type: object
      properties:
        chokepointId:
          type: string
        cargoType:
          type: string
        closurePct:
          type: integer
          format: int32
        options:
          type: array
          items:
            $ref: '#/components/schemas/BypassOption'
        fetchedAt:
          type: string
        primaryChokepointWarRiskTier:
          type: string
          enum:
            - WAR_RISK_TIER_UNSPECIFIED
            - WAR_RISK_TIER_NORMAL
            - WAR_RISK_TIER_ELEVATED
            - WAR_RISK_TIER_HIGH
            - WAR_RISK_TIER_CRITICAL
            - WAR_RISK_TIER_WAR_ZONE
          description: |-
            *
             War risk tier derived from Lloyd's JWC Listed Areas + OSINT threat classification.
             This is a FREE field (no PRO gate) — it exposes the existing server-internal
             threatLevel from ChokepointConfig, making it available to clients for badges
             and bypass corridor scoring.
    BypassOption:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        type:
          type: string
        addedTransitDays:
          type: integer
          format: int32
        addedCostMultiplier:
          type: number
          format: double
        capacityConstraintTonnage:
          type: string
          format: int64
        suitableCargoTypes:
          type: array
          items:
            type: string
        activationThreshold:
          type: string
        waypointChokepointIds:
          type: array
          items:
            type: string
        liveScore:
          type: number
          format: double
        bypassWarRiskTier:
          type: string
          enum:
            - WAR_RISK_TIER_UNSPECIFIED
            - WAR_RISK_TIER_NORMAL
            - WAR_RISK_TIER_ELEVATED
            - WAR_RISK_TIER_HIGH
            - WAR_RISK_TIER_CRITICAL
            - WAR_RISK_TIER_WAR_ZONE
          description: |-
            *
             War risk tier derived from Lloyd's JWC Listed Areas + OSINT threat classification.
             This is a FREE field (no PRO gate) — it exposes the existing server-internal
             threatLevel from ChokepointConfig, making it available to clients for badges
             and bypass corridor scoring.
        notes:
          type: string
    GetCountryCostShockRequest:
      type: object
      properties:
        iso2:
          type: string
          pattern: ^[A-Z]{2}$
          description: ISO 3166-1 alpha-2 country code for the importing country.
        chokepointId:
          type: string
          description: Chokepoint identifier to model as disrupted.
        hs2:
          type: string
          description: 'HS2 chapter (default: "27")'
      required:
        - iso2
        - chokepointId
    GetCountryCostShockResponse:
      type: object
      properties:
        iso2:
          type: string
        chokepointId:
          type: string
        hs2:
          type: string
        supplyDeficitPct:
          type: number
          format: double
          description: >-
            Average refined-product supply deficit % under full closure
            (Gasoline/Diesel/Jet fuel/LPG average; HS 27 only)
        coverageDays:
          type: integer
          format: int32
          description: >-
            Energy stockpile coverage in days (IEA data, HS 27 only; 0 for
            non-energy sectors or net exporters)
        warRiskPremiumBps:
          type: integer
          format: int32
          description: War risk insurance premium in basis points for this chokepoint
        warRiskTier:
          type: string
          enum:
            - WAR_RISK_TIER_UNSPECIFIED
            - WAR_RISK_TIER_NORMAL
            - WAR_RISK_TIER_ELEVATED
            - WAR_RISK_TIER_HIGH
            - WAR_RISK_TIER_CRITICAL
            - WAR_RISK_TIER_WAR_ZONE
          description: |-
            *
             War risk tier derived from Lloyd's JWC Listed Areas + OSINT threat classification.
             This is a FREE field (no PRO gate) — it exposes the existing server-internal
             threatLevel from ChokepointConfig, making it available to clients for badges
             and bypass corridor scoring.
        hasEnergyModel:
          type: boolean
          description: >-
            Whether supply_deficit_pct and coverage_days are modelled (true) or
            unavailable (false)
        unavailableReason:
          type: string
          description: Null/unavailable explanation for non-energy sectors
        fetchedAt:
          type: string
    GetCountryProductsRequest:
      type: object
      properties:
        iso2:
          type: string
          pattern: ^[A-Z]{2}$
          description: >-
            ISO 3166-1 alpha-2 country code whose strategic products should be
            returned.
      required:
        - iso2
    GetCountryProductsResponse:
      type: object
      properties:
        iso2:
          type: string
        products:
          type: array
          items:
            $ref: '#/components/schemas/CountryProduct'
        fetchedAt:
          type: string
          description: >-
            ISO timestamp from the seeded payload (empty when no data is
            cached).
    CountryProduct:
      type: object
      properties:
        hs4:
          type: string
        description:
          type: string
        totalValue:
          type: number
          format: double
        topExporters:
          type: array
          items:
            $ref: '#/components/schemas/ProductExporter'
        year:
          type: integer
          format: int32
    ProductExporter:
      type: object
      properties:
        partnerCode:
          type: integer
          format: int32
        partnerIso2:
          type: string
        value:
          type: number
          format: double
        share:
          type: number
          format: double
    GetMultiSectorCostShockRequest:
      type: object
      properties:
        iso2:
          type: string
          pattern: ^[A-Z]{2}$
          description: ISO 3166-1 alpha-2 country code for the importing country.
        chokepointId:
          type: string
          description: Chokepoint identifier to model as disrupted.
        closureDays:
          type: integer
          format: int32
          description: >-
            Closure-window duration in days. Server clamps to [1, 365]. Defaults
            to 30.
      required:
        - iso2
        - chokepointId
    GetMultiSectorCostShockResponse:
      type: object
      properties:
        iso2:
          type: string
        chokepointId:
          type: string
        closureDays:
          type: integer
          format: int32
          description: Server-clamped closure-window duration in days (1-365).
        warRiskTier:
          type: string
          enum:
            - WAR_RISK_TIER_UNSPECIFIED
            - WAR_RISK_TIER_NORMAL
            - WAR_RISK_TIER_ELEVATED
            - WAR_RISK_TIER_HIGH
            - WAR_RISK_TIER_CRITICAL
            - WAR_RISK_TIER_WAR_ZONE
          description: |-
            *
             War risk tier derived from Lloyd's JWC Listed Areas + OSINT threat classification.
             This is a FREE field (no PRO gate) — it exposes the existing server-internal
             threatLevel from ChokepointConfig, making it available to clients for badges
             and bypass corridor scoring.
        sectors:
          type: array
          items:
            $ref: '#/components/schemas/MultiSectorCostShock'
        totalAddedCost:
          type: number
          format: double
          description: Sum of total_cost_shock across all sectors.
        fetchedAt:
          type: string
        unavailableReason:
          type: string
          description: Populated when no seeded import data is available for the country.
    MultiSectorCostShock:
      type: object
      properties:
        hs2:
          type: string
          description: HS2 chapter code (e.g. "27" mineral fuels, "85" electronics).
        hs2Label:
          type: string
          description: Friendly chapter label (e.g. "Energy", "Electronics").
        importValueAnnual:
          type: number
          format: double
          description: Total annual import value (USD) for this sector.
        freightAddedPctPerTon:
          type: number
          format: double
          description: Bypass-corridor freight uplift fraction (0.10 == +10% per ton).
        warRiskPremiumBps:
          type: integer
          format: int32
          description: >-
            War-risk insurance premium (basis points) sourced from the
            chokepoint tier.
        addedTransitDays:
          type: integer
          format: int32
          description: Bypass-corridor transit penalty (informational).
        totalCostShockPerDay:
          type: number
          format: double
        totalCostShock30Days:
          type: number
          format: double
        totalCostShock90Days:
          type: number
          format: double
        totalCostShock:
          type: number
          format: double
          description: Cost for the requested closure_days window.
        closureDays:
          type: integer
          format: int32
          description: >-
            Echoes the clamped closure duration used for total_cost_shock
            (1-365).
    GetSectorDependencyRequest:
      type: object
      properties:
        iso2:
          type: string
          pattern: ^[A-Z]{2}$
          description: >-
            ISO 3166-1 alpha-2 country code whose sector dependency should be
            analyzed.
        hs2:
          type: string
          description: HS2 chapter code, e.g. "27" (mineral fuels), "85" (electronics)
      required:
        - iso2
        - hs2
    GetSectorDependencyResponse:
      type: object
      properties:
        iso2:
          type: string
        hs2:
          type: string
        hs2Label:
          type: string
          description: Human-readable HS2 chapter name.
        flags:
          type: array
          items:
            type: string
            enum:
              - DEPENDENCY_FLAG_UNSPECIFIED
              - DEPENDENCY_FLAG_SINGLE_SOURCE_CRITICAL
              - DEPENDENCY_FLAG_SINGLE_CORRIDOR_CRITICAL
              - DEPENDENCY_FLAG_COMPOUND_RISK
              - DEPENDENCY_FLAG_DIVERSIFIABLE
            description: >-
              DependencyFlag classifies how a country+sector dependency can
              fail.
        primaryExporterIso2:
          type: string
          description: >-
            ISO2 of the country supplying the largest share of this sector's
            imports.
        primaryExporterShare:
          type: number
          format: double
          description: >-
            Share of imports from the primary exporter (0–1). 0 = no Comtrade
            data available.
        primaryChokepointId:
          type: string
          description: >-
            Chokepoint ID with the highest exposure score for this
            country+sector.
        primaryChokepointExposure:
          type: number
          format: double
          description: Exposure score for the primary chokepoint (0–100).
        hasViableBypass:
          type: boolean
          description: >-
            Whether at least one viable bypass corridor exists for the primary
            chokepoint.
        fetchedAt:
          type: string
    GetRouteExplorerLaneRequest:
      type: object
      properties:
        fromIso2:
          type: string
          pattern: ^[A-Z]{2}$
          description: ISO 3166-1 alpha-2 origin country code for the trade lane.
        toIso2:
          type: string
          pattern: ^[A-Z]{2}$
          description: ISO 3166-1 alpha-2 destination country code for the trade lane.
        hs2:
          type: string
          description: HS2 chapter code, e.g. "27", "85"
        cargoType:
          type: string
          description: 'One of: container, tanker, bulk, roro'
      required:
        - fromIso2
        - toIso2
        - hs2
        - cargoType
    GetRouteExplorerLaneResponse:
      type: object
      properties:
        fromIso2:
          type: string
        toIso2:
          type: string
        hs2:
          type: string
        cargoType:
          type: string
        primaryRouteId:
          type: string
          description: >-
            Primary trade route ID from TRADE_ROUTES config. Empty when no
            modeled lane.
        primaryRouteGeometry:
          type: array
          items:
            $ref: '#/components/schemas/GeoPoint'
        chokepointExposures:
          type: array
          items:
            $ref: '#/components/schemas/ChokepointExposureSummary'
        bypassOptions:
          type: array
          items:
            $ref: '#/components/schemas/BypassCorridorOption'
        warRiskTier:
          type: string
        disruptionScore:
          type: number
          format: double
        estTransitDaysRange:
          $ref: '#/components/schemas/NumberRange'
        estFreightUsdPerTeuRange:
          $ref: '#/components/schemas/NumberRange'
        noModeledLane:
          type: boolean
          description: >-
            True when the wrapper fell back to the origin's first route (no
            shared route
             between origin and destination clusters). Signals "no modeled lane" to the UI.
        fetchedAt:
          type: string
    GeoPoint:
      type: object
      properties:
        lon:
          type: number
          format: double
        lat:
          type: number
          format: double
      description: GeoPoint is a [longitude, latitude] pair.
    ChokepointExposureSummary:
      type: object
      properties:
        chokepointId:
          type: string
        chokepointName:
          type: string
        exposurePct:
          type: integer
          format: int32
    BypassCorridorOption:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        type:
          type: string
        addedTransitDays:
          type: integer
          format: int32
        addedCostMultiplier:
          type: number
          format: double
        warRiskTier:
          type: string
        status:
          type: string
          enum:
            - CORRIDOR_STATUS_UNSPECIFIED
            - CORRIDOR_STATUS_ACTIVE
            - CORRIDOR_STATUS_PROPOSED
            - CORRIDOR_STATUS_UNAVAILABLE
          description: >-
            Status of a bypass corridor for UI labeling. "active" means usable
            today;
             "proposed" means documented but not yet built/operational; "unavailable"
             means blockaded or otherwise blocked from use.
        fromPort:
          $ref: '#/components/schemas/GeoPoint'
        toPort:
          $ref: '#/components/schemas/GeoPoint'
      description: >-
        BypassCorridorOption is a single enriched bypass corridor for the Route
        Explorer UI.
         Includes coordinate endpoints so the client can call MapContainer.setBypassRoutes
         directly without any client-side geometry lookup.
    NumberRange:
      type: object
      properties:
        min:
          type: integer
          format: int32
        max:
          type: integer
          format: int32
      description: Inclusive integer range for transit days / freight USD estimates.
    GetRouteImpactRequest:
      type: object
      properties:
        fromIso2:
          type: string
          pattern: ^[A-Z]{2}$
          description: ISO 3166-1 alpha-2 origin country code for the route.
        toIso2:
          type: string
          pattern: ^[A-Z]{2}$
          description: ISO 3166-1 alpha-2 destination country code for the route.
        hs2:
          type: string
          description: HS2 chapter code for the product sector on the route.
      required:
        - fromIso2
        - toIso2
        - hs2
    GetRouteImpactResponse:
      type: object
      properties:
        laneValueUsd:
          type: number
          format: double
        primaryExporterIso2:
          type: string
        primaryExporterShare:
          type: number
          format: double
        topStrategicProducts:
          type: array
          items:
            $ref: '#/components/schemas/StrategicProduct'
        resilienceScore:
          type: number
          format: double
        dependencyFlags:
          type: array
          items:
            type: string
            enum:
              - DEPENDENCY_FLAG_UNSPECIFIED
              - DEPENDENCY_FLAG_SINGLE_SOURCE_CRITICAL
              - DEPENDENCY_FLAG_SINGLE_CORRIDOR_CRITICAL
              - DEPENDENCY_FLAG_COMPOUND_RISK
              - DEPENDENCY_FLAG_DIVERSIFIABLE
            description: >-
              DependencyFlag classifies how a country+sector dependency can
              fail.
        hs2InSeededUniverse:
          type: boolean
        comtradeSource:
          type: string
        fetchedAt:
          type: string
    StrategicProduct:
      type: object
      properties:
        hs4:
          type: string
        label:
          type: string
        totalValueUsd:
          type: number
          format: double
        topExporterIso2:
          type: string
        topExporterShare:
          type: number
          format: double
        primaryChokepointId:
          type: string
    ListPipelinesRequest:
      type: object
      properties:
        commodityType:
          type: string
          description: Filter to one commodity. Omit (or pass empty) to receive both.
      description: |-
        ListPipelines returns the full oil and/or gas pipeline registry with
         evidence-based status per asset. Registry is curated (see
         docs/methodology/pipelines.mdx) and refreshed weekly by
         scripts/seed-pipelines-{gas,oil}.mjs. Typical consumer: PipelineStatusPanel
         rendering the DeckGL PathLayer.

         The public badge is DERIVED from the evidence bundle server-side at
         read time — callers MUST use `public_badge` for display, not invent
         their own derivation from `evidence` fields. This keeps the atlas and
         MCP clients consistent and versioned together.
    ListPipelinesResponse:
      type: object
      properties:
        pipelines:
          type: array
          items:
            $ref: '#/components/schemas/PipelineEntry'
        fetchedAt:
          type: string
        classifierVersion:
          type: string
        upstreamUnavailable:
          type: boolean
    PipelineEntry:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        operator:
          type: string
        commodityType:
          type: string
          description: Either "gas" or "oil".
        fromCountry:
          type: string
        toCountry:
          type: string
        transitCountries:
          type: array
          items:
            type: string
        capacityBcmYr:
          type: number
          format: double
        capacityMbd:
          type: number
          format: double
        lengthKm:
          type: integer
          format: int32
        inService:
          type: integer
          format: int32
        startPoint:
          $ref: '#/components/schemas/LatLon'
        endPoint:
          $ref: '#/components/schemas/LatLon'
        waypoints:
          type: array
          items:
            $ref: '#/components/schemas/LatLon'
        evidence:
          $ref: '#/components/schemas/PipelineEvidence'
        publicBadge:
          type: string
          description: |-
            Server-derived public badge. One of:
               "flowing" | "reduced" | "offline" | "disputed"
    LatLon:
      type: object
      properties:
        lat:
          type: number
          format: double
        lon:
          type: number
          format: double
    PipelineEvidence:
      type: object
      properties:
        physicalState:
          type: string
          description: 'One of: "flowing" | "reduced" | "offline" | "unknown"'
        physicalStateSource:
          type: string
          description: >-
            One of: "operator" | "regulator" | "press" | "satellite" |
            "ais-relay"
        operatorStatement:
          $ref: '#/components/schemas/OperatorStatement'
        commercialState:
          type: string
          description: 'One of: "under_contract" | "expired" | "suspended" | "unknown"'
        sanctionRefs:
          type: array
          items:
            $ref: '#/components/schemas/SanctionRef'
        lastEvidenceUpdate:
          type: string
        classifierVersion:
          type: string
        classifierConfidence:
          type: number
          format: double
    OperatorStatement:
      type: object
      properties:
        text:
          type: string
        url:
          type: string
        date:
          type: string
    SanctionRef:
      type: object
      properties:
        authority:
          type: string
        listId:
          type: string
        date:
          type: string
        url:
          type: string
    GetPipelineDetailRequest:
      type: object
      properties:
        pipelineId:
          type: string
          description: Pipeline identifier to load with full evidence details.
      required:
        - pipelineId
      description: >-
        GetPipelineDetail returns a single pipeline with its full evidence
        bundle.
         Evidence surface here is richer than ListPipelinesResponse — the list view
         is designed for the map layer's compact shape; detail is designed for the
         click-through drawer.
    GetPipelineDetailResponse:
      type: object
      properties:
        pipeline:
          $ref: '#/components/schemas/PipelineEntry'
        revisions:
          type: array
          items:
            $ref: '#/components/schemas/PipelineRevisionEntry'
        fetchedAt:
          type: string
        unavailable:
          type: boolean
    PipelineRevisionEntry:
      type: object
      properties:
        date:
          type: string
        fieldChanged:
          type: string
        previousValue:
          type: string
        newValue:
          type: string
        trigger:
          type: string
          description: 'One of: "classifier" | "source" | "decay" | "override"'
        sourcesUsed:
          type: array
          items:
            type: string
        classifierVersion:
          type: string
    ListStorageFacilitiesRequest:
      type: object
      properties:
        facilityType:
          type: string
          description: |-
            Filter to one facility type. Accepts:
               "ugs" | "spr" | "lng_export" | "lng_import" | "crude_tank_farm"
             Omit (or pass empty) to receive all types.
      description: |-
        ListStorageFacilities returns the curated strategic storage registry
         (underground gas storage, strategic petroleum reserves, LNG terminals,
         crude tank farms) with evidence-based status per asset. Registry is
         curated (see docs/methodology/storage.mdx) and refreshed weekly by
         scripts/seed-storage-facilities.mjs. Typical consumer:
         StorageFacilityMapPanel rendering the DeckGL ScatterplotLayer.

         Like pipelines, the public badge is DERIVED from the evidence bundle
         server-side at read time. Callers MUST use `public_badge` for display
         rather than inventing their own derivation from `evidence` fields, so
         the atlas and MCP clients stay consistent and versioned together.
    ListStorageFacilitiesResponse:
      type: object
      properties:
        facilities:
          type: array
          items:
            $ref: '#/components/schemas/StorageFacilityEntry'
        fetchedAt:
          type: string
        classifierVersion:
          type: string
        upstreamUnavailable:
          type: boolean
    StorageFacilityEntry:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        operator:
          type: string
        facilityType:
          type: string
          description: >-
            One of: "ugs" | "spr" | "lng_export" | "lng_import" |
            "crude_tank_farm"
        country:
          type: string
        location:
          $ref: '#/components/schemas/StorageLatLon'
        capacityTwh:
          type: number
          format: double
          description: >-
            Working capacity in the facility's native unit (see
            working_capacity_unit).
             Exactly ONE of these is populated per facility, chosen by facility_type:
               ugs                              → capacity_twh
               spr, crude_tank_farm             → capacity_mb
               lng_export, lng_import           → capacity_mtpa
        capacityMb:
          type: number
          format: double
        capacityMtpa:
          type: number
          format: double
        workingCapacityUnit:
          type: string
          description: 'One of: "TWh" | "Mb" | "Mtpa"'
        inService:
          type: integer
          format: int32
        evidence:
          $ref: '#/components/schemas/StorageEvidence'
        publicBadge:
          type: string
          description: |-
            Server-derived public badge. One of:
               "operational" | "reduced" | "offline" | "disputed"
    StorageLatLon:
      type: object
      properties:
        lat:
          type: number
          format: double
        lon:
          type: number
          format: double
    StorageEvidence:
      type: object
      properties:
        physicalState:
          type: string
          description: >-
            One of: "operational" | "reduced" | "offline" | "under_construction"
            | "unknown"
        physicalStateSource:
          type: string
          description: >-
            One of: "operator" | "regulator" | "press" | "satellite" |
            "ais-relay"
        operatorStatement:
          $ref: '#/components/schemas/StorageOperatorStatement'
        commercialState:
          type: string
          description: 'One of: "under_contract" | "expired" | "suspended" | "unknown"'
        sanctionRefs:
          type: array
          items:
            $ref: '#/components/schemas/StorageSanctionRef'
        fillDisclosed:
          type: boolean
          description: >-
            Whether working-gas / stock-level fill is publicly disclosed for
            this
             asset. LNG export terminals, for instance, tend NOT to disclose; UGS
             sites in Europe are required to disclose via GIE AGSI+.
        fillSource:
          type: string
          description: |-
            Source of the disclosed fill series ("GIE AGSI+", "EIA SPR weekly
             stock report", etc.). Empty when fill_disclosed=false.
        lastEvidenceUpdate:
          type: string
        classifierVersion:
          type: string
        classifierConfidence:
          type: number
          format: double
    StorageOperatorStatement:
      type: object
      properties:
        text:
          type: string
        url:
          type: string
        date:
          type: string
    StorageSanctionRef:
      type: object
      properties:
        authority:
          type: string
        listId:
          type: string
        date:
          type: string
        url:
          type: string
    GetStorageFacilityDetailRequest:
      type: object
      properties:
        facilityId:
          type: string
          description: Storage facility identifier to load with full evidence details.
      required:
        - facilityId
      description: >-
        GetStorageFacilityDetail returns a single facility with its full
        evidence
         bundle + revision log. Revisions land in Week 3 alongside the disruption
         event log (Week 3 milestone — empty array in v1).
    GetStorageFacilityDetailResponse:
      type: object
      properties:
        facility:
          $ref: '#/components/schemas/StorageFacilityEntry'
        revisions:
          type: array
          items:
            $ref: '#/components/schemas/StorageFacilityRevisionEntry'
        fetchedAt:
          type: string
        unavailable:
          type: boolean
    StorageFacilityRevisionEntry:
      type: object
      properties:
        date:
          type: string
        fieldChanged:
          type: string
        previousValue:
          type: string
        newValue:
          type: string
        trigger:
          type: string
          description: 'One of: "classifier" | "source" | "decay" | "override"'
        sourcesUsed:
          type: array
          items:
            type: string
        classifierVersion:
          type: string
    ListFuelShortagesRequest:
      type: object
      properties:
        country:
          type: string
          description: Filter to one ISO 3166-1 alpha-2 country. Omit for global.
        product:
          type: string
          description: >-
            Filter to one product. Accepts: "petrol" | "diesel" | "jet" |
            "heating_oil".
             Omit for all products.
        severity:
          type: string
          description: >-
            Filter to one severity. Accepts: "confirmed" | "watch". Omit for
            both.
      description: |-
        ListFuelShortages returns the global fuel-shortage alert registry.
         Seeded from a curated JSON file (scripts/data/fuel-shortages.json).
         An LLM classifier extension was scoped but not shipped — the registry
         is curated-only today. Severity ("confirmed" or "watch") is a row
         field authored at curation time; the evidence is shipped alongside
         so agents and humans can audit the grounds for a severity label.

         See docs/methodology/shortages.mdx for the evidence-threshold spec.
    ListFuelShortagesResponse:
      type: object
      properties:
        shortages:
          type: array
          items:
            $ref: '#/components/schemas/FuelShortageEntry'
        fetchedAt:
          type: string
        classifierVersion:
          type: string
        upstreamUnavailable:
          type: boolean
    FuelShortageEntry:
      type: object
      properties:
        id:
          type: string
        country:
          type: string
        product:
          type: string
          description: 'One of: "petrol" | "diesel" | "jet" | "heating_oil"'
        severity:
          type: string
          description: >-
            One of: "confirmed" | "watch"  (classifier output — not a
            client-side derivation)
        firstSeen:
          type: string
        lastConfirmed:
          type: string
        resolvedAt:
          type: string
          description: Empty string when not yet resolved.
        impactTypes:
          type: array
          items:
            type: string
            description: |-
              Observable consumer-facing impacts. Subset of:
                 "stations_closed" | "rationing" | "flights_cancelled" | "import_cut" | "price_spike"
        causeChain:
          type: array
          items:
            type: string
            description: |-
              Contributing root causes, ordered primary-first. Subset of:
                 "upstream_refinery" | "logistics" | "policy" | "chokepoint" |
                 "sanction" | "war" | "import_cut"
        shortDescription:
          type: string
        evidence:
          $ref: '#/components/schemas/FuelShortageEvidence'
    FuelShortageEvidence:
      type: object
      properties:
        evidenceSources:
          type: array
          items:
            $ref: '#/components/schemas/FuelShortageEvidenceSource'
        firstRegulatorConfirmation:
          type: string
          description: |-
            ISO date of the first regulator confirmation, if any. Empty when
             severity is "watch" on press-only signal.
        classifierVersion:
          type: string
        classifierConfidence:
          type: number
          format: double
        lastEvidenceUpdate:
          type: string
    FuelShortageEvidenceSource:
      type: object
      properties:
        authority:
          type: string
        title:
          type: string
        url:
          type: string
        date:
          type: string
        sourceType:
          type: string
          description: >-
            One of: "regulator" | "operator" | "press" | "ais-relay" |
            "satellite"
    GetFuelShortageDetailRequest:
      type: object
      properties:
        shortageId:
          type: string
          description: Fuel-shortage identifier to load with full evidence details.
      required:
        - shortageId
      description: |-
        GetFuelShortageDetail returns a single shortage with full evidence
         bundle + citation timeline. Loaded lazily on drawer open.
    GetFuelShortageDetailResponse:
      type: object
      properties:
        shortage:
          $ref: '#/components/schemas/FuelShortageEntry'
        fetchedAt:
          type: string
        unavailable:
          type: boolean
    ListEnergyDisruptionsRequest:
      type: object
      properties:
        assetId:
          type: string
          description: |-
            Filter to one asset. Omit for all. When set, also narrows to the
             matching asset_type if provided.
        assetType:
          type: string
          description: 'Filter to one asset type. Accepts: "pipeline" | "storage".'
        ongoingOnly:
          type: boolean
          description: If true, only return events with endAt empty (still ongoing).
      description: |-
        ListEnergyDisruptions returns the energy disruption event log — state
         transitions for pipelines and storage facilities (sabotage, sanction,
         maintenance, mechanical, weather, commercial, war). Each event ties
         back to an assetId seeded by the pipeline or storage registry, so the
         panel drawer can render an asset-scoped timeline without a second RPC.

         Seeded from a curated JSON file (scripts/data/energy-disruptions.json).
         An automated state-transition classifier was scoped but not shipped —
         the log is curated-only today.

         See docs/methodology/disruptions.mdx.
    ListEnergyDisruptionsResponse:
      type: object
      properties:
        events:
          type: array
          items:
            $ref: '#/components/schemas/EnergyDisruptionEntry'
        fetchedAt:
          type: string
        classifierVersion:
          type: string
        upstreamUnavailable:
          type: boolean
    EnergyDisruptionEntry:
      type: object
      properties:
        id:
          type: string
        assetId:
          type: string
          description: Maps to a pipeline or storage-facility id seeded elsewhere.
        assetType:
          type: string
          description: 'One of: "pipeline" | "storage"'
        eventType:
          type: string
          description: |-
            One of: "sabotage" | "sanction" | "maintenance" | "mechanical" |
                     "weather" | "commercial" | "war" | "other"
        startAt:
          type: string
        endAt:
          type: string
          description: Empty string when event is still ongoing.
        capacityOfflineBcmYr:
          type: number
          format: double
          description: Headline-offline capacity (contextual — 0 when not applicable).
        capacityOfflineMbd:
          type: number
          format: double
        causeChain:
          type: array
          items:
            type: string
            description: Contributing causes, primary-first.
        shortDescription:
          type: string
        sources:
          type: array
          items:
            $ref: '#/components/schemas/EnergyDisruptionSource'
        classifierVersion:
          type: string
        classifierConfidence:
          type: number
          format: double
        lastEvidenceUpdate:
          type: string
        countries:
          type: array
          items:
            type: string
            description: |-
              Countries touched by the referenced asset (pipeline: fromCountry +
               toCountry + transitCountries; storage: country). Denormalised at seed
               time so CountryDeepDivePanel can filter events without a second RPC.
               Always non-empty in well-formed payloads; empty only if the upstream
               asset was removed without an event update. Per plan §R/#5 decision B.
    EnergyDisruptionSource:
      type: object
      properties:
        authority:
          type: string
        title:
          type: string
        url:
          type: string
        date:
          type: string
        sourceType:
          type: string
    GetChinaCorridorControlTowersRequest:
      type: object
    GetChinaCorridorControlTowersResponse:
      type: object
      properties:
        payloadJson:
          contentMediaType: application/json
          contentSchema:
            $ref: '#/components/schemas/ChinaCorridorControlTowerResponse'
          type: string
          description: >-
            Canonical JSON keeps the shared #5581 provenance envelope
            byte-for-byte
             equivalent across cache, API, UI, and later MCP adapters.
        generatedAt:
          type: string
        upstreamUnavailable:
          description: >-
            True only when every reviewed corridor is unavailable. Agents and
            API callers must treat true as upstream degradation, not as evidence
            that corridor conditions are normal or zero.
          type: boolean
