{
  "openapi": "3.1.0",
  "info": {
    "title": "Norric Intelligence API",
    "version": "2.0.0",
    "description": "Machine-readable Norric MCP discovery and x402 payment contract for autonomous agents. Anonymous discovery, status and freshness are free; paid tools use exact test-USDC quotes on Base Sepolia testnet."
  },
  "servers": [
    {
      "url": "https://mcp.norric.io",
      "description": "Norric MCP service"
    }
  ],
  "externalDocs": {
    "description": "Norric developer guide",
    "url": "https://norric.io/docs"
  },
  "tags": [
    {
      "name": "Service",
      "description": "Public service status"
    },
    {
      "name": "MCP",
      "description": "Model Context Protocol over Streamable HTTP"
    },
    {
      "name": "Intelligence REST",
      "description": "Selected live intelligence calls without an MCP session handshake"
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "tags": [
          "Service"
        ],
        "summary": "Get service and pipeline health",
        "operationId": "getHealth",
        "security": [],
        "responses": {
          "200": {
            "description": "Current service status, tool count, product statistics, and pipeline freshness",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          }
        }
      }
    },
    "/mcp": {
      "post": {
        "tags": [
          "MCP"
        ],
        "summary": "Send an MCP JSON-RPC request",
        "description": "Streamable HTTP MCP endpoint. Anonymous agents may initialize, list tools, call free status/freshness, and call explicitly payment-gated tools. An unpaid paid-tool call returns an x402 challenge; retry with the signed payload in params._meta['x402/payment']. Other anonymous tool calls are rejected. API-key clients remain supported.",
        "operationId": "postMcpRequest",
        "security": [],
        "parameters": [
          {
            "name": "mcp-session-id",
            "in": "header",
            "required": false,
            "description": "Session ID returned by initialization; required for subsequent session-bound requests.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Accept",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "const": "application/json, text/event-stream"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonRpcRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "MCP JSON-RPC response or event stream",
            "headers": {
              "mcp-session-id": {
                "description": "Session ID issued during initialization",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Wait 60 seconds and retry once."
          },
          "503": {
            "description": "Data source temporarily unavailable. Retry after five minutes."
          },
          "403": {
            "description": "Anonymous caller requested a tool that is neither free nor payment-gated."
          }
        }
      }
    },
    "/api/v1/score/{orgnr}": {
      "get": {
        "tags": [
          "Intelligence REST"
        ],
        "summary": "Get a full company intelligence score package",
        "operationId": "getCompanyScore",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "norricApiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgnrPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Company identity, risk score, signals, timeline and procurement context",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NorricEnvelope"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "description": "Invalid organisation number"
          }
        }
      }
    },
    "/api/v1/search": {
      "get": {
        "tags": [
          "Intelligence REST"
        ],
        "summary": "Search companies by name or organisation number prefix",
        "operationId": "searchCompanies",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "norricApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching monitored companies",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NorricEnvelope"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/v1/contagion-map/{orgnr}": {
      "get": {
        "tags": [
          "Intelligence REST"
        ],
        "summary": "Get a probabilistic supply-chain contagion map",
        "operationId": "getContagionMap",
        "description": "Returns geographic peer rings inferred from shared procurement sector and proximity. Relationships are probabilistic, not verified supply-chain links.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "norricApiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgnrPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Source company, peer rings and aggregate summary",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NorricEnvelope"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "description": "Invalid organisation number"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Norric API key in the Authorization header."
      },
      "norricApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Norric-Key",
        "description": "Alternative API-key header. Authorization takes precedence when both headers are sent."
      }
    },
    "schemas": {
      "JsonRpcRequest": {
        "type": "object",
        "required": [
          "jsonrpc",
          "method"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "method": {
            "type": "string",
            "examples": [
              "initialize",
              "tools/list",
              "tools/call"
            ]
          },
          "params": {
            "type": "object",
            "additionalProperties": true
          }
        },
        "additionalProperties": false
      },
      "JsonRpcResponse": {
        "type": "object",
        "required": [
          "jsonrpc"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "result": {},
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "integer"
              },
              "message": {
                "type": "string"
              },
              "data": {}
            },
            "additionalProperties": true
          }
        },
        "additionalProperties": true
      },
      "HealthResponse": {
        "type": "object",
        "required": [
          "status",
          "mcp_tools",
          "version"
        ],
        "properties": {
          "status": {
            "type": "string",
            "examples": [
              "ok",
              "degraded"
            ]
          },
          "mcp_tools": {
            "type": "integer",
            "minimum": 0
          },
          "version": {
            "type": "string"
          },
          "products": {
            "type": "object",
            "additionalProperties": true
          },
          "pipeline_freshness": {
            "type": "object",
            "additionalProperties": true
          }
        },
        "additionalProperties": true
      },
      "AuthError": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "NorricEnvelope": {
        "type": "object",
        "required": [
          "data",
          "metadata",
          "signals",
          "warnings"
        ],
        "properties": {
          "data": {
            "type": "object",
            "additionalProperties": true
          },
          "metadata": {
            "$ref": "#/components/schemas/NorricMetadata"
          },
          "signals": {
            "type": "array",
            "items": {}
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": false
      },
      "NorricMetadata": {
        "type": "object",
        "required": [
          "response_id",
          "tool",
          "source",
          "fetched_at",
          "confidence",
          "cache_ttl_seconds",
          "is_cached"
        ],
        "properties": {
          "response_id": {
            "type": "string"
          },
          "tool": {
            "type": "string"
          },
          "source": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "fetched_at": {
            "type": "string",
            "format": "date-time"
          },
          "confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "cache_ttl_seconds": {
            "type": "integer",
            "minimum": 0
          },
          "is_cached": {
            "type": "boolean"
          }
        },
        "additionalProperties": true
      }
    },
    "parameters": {
      "OrgnrPath": {
        "name": "orgnr",
        "in": "path",
        "required": true,
        "description": "Swedish organisation number, with or without a dash.",
        "schema": {
          "type": "string",
          "pattern": "^[0-9]{6}-?[0-9]{4}$",
          "examples": [
            "556012-3456"
          ]
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid API key",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/AuthError"
            }
          }
        }
      }
    }
  },
  "x-norric-mcp": {
    "protocolVersion": "2024-11-05",
    "transport": "streamable-http",
    "registryName": "io.github.gucceed/norric-mcp",
    "registryUrl": "https://registry.modelcontextprotocol.io/v0.1/servers?search=norric",
    "apiKeyUrl": "https://norric.io/api-keys"
  },
  "x-norric-x402": {
    "status": "review stack after wallet-only PR #25",
    "network": "eip155:84532",
    "networkName": "Base Sepolia testnet",
    "mainnetAllowed": false,
    "facilitator": "https://x402-facilitator-production-5948.up.railway.app/",
    "paymentMetaPath": "params._meta[\"x402/payment\"]",
    "settlementMetaPath": "result._meta[\"x402/payment-response\"]",
    "freeTools": [
      "norric_status_v1",
      "norric_data_freshness_v1"
    ],
    "priceBandsAtomicTestUsdc": {
      "lookup": 2000,
      "signal": 5000,
      "evidence": 10000,
      "feed_batch": 20000,
      "heavy": 50000
    },
    "pricedTools": {
      "kreditvakt_score_company_v1": {
        "band": "lookup",
        "amount": 2000
      }
    },
    "note": "Watchlist/event metering is not live."
  }
}
