{
  "openapi": "3.0.3",
  "info": {
    "title": "Nordic Data API",
    "version": "1.6.0",
    "description": "Global B2B intelligence for AI agents \u2014 38M+ canonical companies across 30+ countries (US 26.5M, UK 5.9M, Norway 1.22M, Sweden 1.20M, Finland 471K, Denmark 112K, plus Germany, France, Italy, Spain, Netherlands, India, Cayman, BVI and 280+ more via the global LEI graph), 1.6M-entity sanctions screen, per-fact provenance, cross-jurisdiction officer match, 78 MCP tools. Unified v1 + v2 surface \u2014 every endpoint the MCP server exposes is documented here.\n\n## Rate limits\nEvery authenticated response includes Stripe-style rate-limit headers:\n\n- X-RateLimit-Limit \u2014 your monthly request quota\n- X-RateLimit-Remaining \u2014 calls left in this billing month\n- X-RateLimit-Reset \u2014 Unix timestamp when the quota resets\n- X-RateLimit-Policy \u2014 e.g. \"100;w=monthly\"\n\nWhen you exceed your quota the API returns 429 with a Retry-After header (seconds until reset).",
    "contact": {
      "name": "Nordic Data support",
      "email": "support@nordicdata.cloud",
      "url": "https://nordicdata.cloud"
    },
    "license": {
      "name": "Commercial",
      "url": "https://nordicdata.cloud/legal/terms"
    }
  },
  "servers": [
    {
      "url": "https://api.nordicdata.cloud",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "tags": [
    {
      "name": "Lookup",
      "description": "Resolve and fetch canonical company records"
    },
    {
      "name": "Search",
      "description": "Fuzzy + prefix name search across 35M companies"
    },
    {
      "name": "Provenance",
      "description": "Per-fact source + confidence + freshness"
    },
    {
      "name": "Contacts",
      "description": "Verified emails + phones with multi-signal confidence scoring"
    },
    {
      "name": "KYB",
      "description": "Know-Your-Business pack and signals"
    },
    {
      "name": "Officers",
      "description": "Director / officer graph and cross-jurisdiction matching"
    },
    {
      "name": "Sanctions",
      "description": "1.6M-entity sanctions / PEP screening"
    },
    {
      "name": "Enrichment",
      "description": "Just-in-time enrichment jobs"
    },
    {
      "name": "GDPR",
      "description": "Article 15 (access) + Article 17 (erasure) self-serve"
    },
    {
      "name": "Status",
      "description": "Service health + dataset freshness"
    },
    {
      "name": "Account",
      "description": "API-key + signup"
    },
    {
      "name": "Agent buying",
      "description": "Endpoints designed for autonomous agents to discover plans, subscribe with a Stripe payment method, and change plans \u2014 no browser, no email round-trip, no Customer Portal"
    },
    {
      "name": "Companies (Norway)",
      "description": "Norwegian company data \u2014 identity, officers, accounts, ownership, ~1M+ companies"
    },
    {
      "name": "Companies (Multi-Nordic)",
      "description": "Sweden, Denmark, Finland company lookups"
    },
    {
      "name": "Persons",
      "description": "Officer + board-member network with shortest-path queries"
    },
    {
      "name": "Shareholders",
      "description": "Norwegian shareholder cap tables (3M+ ownership positions across 396K companies)"
    },
    {
      "name": "Tech",
      "description": "Website tech-stack fingerprinting"
    },
    {
      "name": "Tenders",
      "description": "Public procurement notices across 5 Nordic countries"
    },
    {
      "name": "Awards",
      "description": "Public-procurement contract awards (5 Nordic countries)"
    },
    {
      "name": "Companies (US)",
      "description": "918K+ verified active US businesses, filter by industry (NAICS) \u00d7 state \u00d7 employee count"
    },
    {
      "name": "Lead enrichment",
      "description": "Domain-first or name-first composite enrichment: identity + website + tech stack + email provider + social URLs + contacts + named executives"
    },
    {
      "name": "Contact discovery",
      "description": "Sales-shaped: filter by industry + role + region + size \u2192 flat list of contacts with email + phone, ready to import"
    },
    {
      "name": "Webhooks",
      "description": "Event-driven subscriptions"
    }
  ],
  "paths": {
    "/v2/companies/search": {
      "get": {
        "tags": [
          "Search"
        ],
        "summary": "Fuzzy + prefix name search",
        "description": "Sub-200ms search across 35M canonical companies. Prefix-first strategy: btree partial index per country, falls back to trigram fuzzy match when prefix returns fewer than half the limit.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "equinor"
          },
          {
            "name": "country",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "NO"
            },
            "description": "ISO-2 country filter (NO, SE, FI, DK, GB, US, DE, FR, IT, NL, ES)"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Search results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v2/companies/{canonical_id}": {
      "get": {
        "tags": [
          "Lookup"
        ],
        "summary": "Full canonical company record with per-fact provenance",
        "description": "Returns the canonical company plus every fact (address, employees, industry, website, etc.) with source + confidence + fetched_at for each.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CanonicalId"
          }
        ],
        "responses": {
          "200": {
            "description": "Company with facts + provenance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CanonicalCompany"
                }
              }
            }
          },
          "404": {
            "description": "Not found"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v2/companies/{canonical_id}/provenance": {
      "get": {
        "tags": [
          "Provenance"
        ],
        "summary": "Per-fact provenance",
        "description": "For any canonical_id, returns every fact with its source, confidence, fetched_at, and verified_at. Unique to Nordic Data \u2014 no other provider exposes per-field sourcing.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CanonicalId"
          }
        ],
        "responses": {
          "200": {
            "description": "Facts array",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "canonical_id": {
                      "type": "string"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "facts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Fact"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v2/companies/{canonical_id}/contacts": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "Tiered verified emails + phones with confidence",
        "description": "Returns all crawled emails and phones for the company. Each email carries composite_confidence (0..1) derived from multi-signal scoring: MX verified, page-context, pattern-match, person-attribution. Filter with min_confidence query parameter.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CanonicalId"
          },
          {
            "name": "min_confidence",
            "in": "query",
            "schema": {
              "type": "number",
              "default": 0,
              "minimum": 0,
              "maximum": 1
            },
            "description": "Filter emails by composite confidence score. 0.8+ = Tier A (high), 0.5+ = Tier B, <0.5 = Tier C"
          }
        ],
        "responses": {
          "200": {
            "description": "Emails + phones grouped by tier",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v2/companies/{canonical_id}/global-officers": {
      "get": {
        "tags": [
          "Officers"
        ],
        "summary": "Cross-jurisdiction officer match",
        "description": "Returns every company every director of this company also sits on. Officer coverage spans **NO + SE + US (NY, PA, OR state filings \u2014 8.7M roles)** today, with UK + DK + FI on the roadmap. Default mode uses exact name match + birth-year disambiguation when both sides have DOB (sub-100ms). Pass ?fuzzy=true to also match name variants (Andre J. -> Andre Johansen) via trigram similarity \u2014 slower (~2-3s for large boards) but catches cross-registry spelling differences. The response includes a coverage_note + coverage_status field telling you whether the company is covered.\n\n**Disambiguation caveat:** Norwegian officer data includes date-of-birth, so when both sides of a match have a DOB the year must agree (match_type=\"exact_with_birth\"). US state filings do not include DOB, so US-to-US matches rely on exact-name only (match_type=\"exact_name\") \u2014 common names like \"John Smith\" will collide. The match_score + match_type fields on each result let you filter for high-confidence matches if needed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CanonicalId"
          },
          {
            "name": "fuzzy",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "If true, also match name variants via trigram similarity. Slower (~2-3s for 10+ officers). Default false (sub-100ms exact match)."
          }
        ],
        "responses": {
          "200": {
            "description": "Officers with cross-company role overlap. Includes coverage_status when country not indexed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "canonical_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "country": {
                      "type": "string"
                    },
                    "officers_with_overlap": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "officer": {
                            "type": "string"
                          },
                          "born": {
                            "type": "string",
                            "format": "date",
                            "nullable": true
                          },
                          "also_directs": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "orgnr": {
                                  "type": "string"
                                },
                                "name": {
                                  "type": "string"
                                },
                                "born": {
                                  "type": "string",
                                  "format": "date",
                                  "nullable": true
                                },
                                "match_type": {
                                  "type": "string",
                                  "enum": [
                                    "exact_with_birth",
                                    "exact_name",
                                    "fuzzy_name"
                                  ],
                                  "description": "exact_with_birth = both sides have DOB and they agree (highest confidence, NO-to-NO or NO-to-US-with-DOB). exact_name = names match exactly but at least one side lacks DOB (US-to-US, US-to-NO). fuzzy_name = trigram similarity \u22650.7 (only present when ?fuzzy=true)."
                                },
                                "match_score": {
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 1
                                }
                              }
                            }
                          },
                          "count": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "coverage_note": {
                      "type": "string",
                      "example": "Officer network spans NO + SE + US (NY, PA, OR state filings \u2014 8.7M roles). UK + DK + FI scheduled.",
                      "description": "Plain-English description of which jurisdictions are currently indexed."
                    },
                    "coverage_status": {
                      "type": "string",
                      "enum": [
                        "ok",
                        "no_data_for_country"
                      ],
                      "description": "ok = officer data is available for this company's country; no_data_for_country = company is real but its country's officer registry isn't indexed yet."
                    },
                    "fuzzy_enabled": {
                      "type": "boolean"
                    },
                    "fuzzy_hint": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "Feature not in plan (upgrade to Pro)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v2/companies/{canonical_id}/related-by-domain": {
      "get": {
        "tags": [
          "Lookup"
        ],
        "summary": "Sister entities sharing a domain",
        "description": "Returns companies that share an email or web domain with this one. Useful for discovering sister entities not visible through formal corporate filings.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CanonicalId"
          }
        ],
        "responses": {
          "200": {
            "description": "Related entities",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "canonical_id": {
                      "type": "string"
                    },
                    "related": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Company"
                      }
                    },
                    "count": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/resolve/{scheme}/{external_id}": {
      "get": {
        "tags": [
          "Lookup"
        ],
        "summary": "Universal external-ID resolver",
        "description": "Resolves any external identifier (orgnr, LEI, EIN, CVR, UK CH number, sanctions IDs, etc.) to the canonical Nordic Data company record. 310 schemes supported.",
        "parameters": [
          {
            "name": "scheme",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "orgnr_no",
            "description": "Scheme name: orgnr_no, orgnr_se, business_id_fi, cvr_dk, ch_uk, us_registry, lei, ein, duns, sanctions_id, etc."
          },
          {
            "name": "external_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "923609016"
          }
        ],
        "responses": {
          "200": {
            "description": "Resolved entity",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "resolved": {
                      "type": "boolean"
                    },
                    "canonical_id": {
                      "type": "string"
                    },
                    "country": {
                      "type": "string"
                    },
                    "registry_id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "External ID not found"
          }
        }
      }
    },
    "/sanctions/search": {
      "get": {
        "tags": [
          "Sanctions"
        ],
        "summary": "Search 1.6M-entity sanctions list",
        "description": "Fuzzy search the global sanctions + PEP database \u2014 composite coverage across major international + national lists.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "Vladimir Putin"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matches sorted by similarity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SanctionsMatches"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/sanctions/screen-bulk": {
      "post": {
        "tags": [
          "Sanctions"
        ],
        "summary": "Bulk-screen up to 100 names",
        "description": "Submit a list of names; get top-3 matches per name from the 1.6M-entity database.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "names"
                ],
                "properties": {
                  "names": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 100,
                    "example": [
                      "Vladimir Putin",
                      "Acme Corp"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Results per name",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "query": {
                            "type": "string"
                          },
                          "matches": {
                            "type": "array"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "Feature not in plan (upgrade to Pro)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/companies/{canonical_id}/enrich": {
      "post": {
        "tags": [
          "Enrichment"
        ],
        "summary": "Queue JIT enrichment job",
        "description": "Triggers asynchronous enrichment of a company's contacts. Returns immediately with a job_id. Worker drains the queue every 2 minutes. Poll /enrichment/jobs/{job_id} or subscribe to enrichment.completed webhook.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CanonicalId"
          }
        ],
        "responses": {
          "200": {
            "description": "Job enqueued or cached",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "enqueued",
                        "cached"
                      ]
                    },
                    "job_id": {
                      "type": "string"
                    },
                    "check_url": {
                      "type": "string"
                    },
                    "estimated_seconds": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/enrichment/jobs/{job_id}": {
      "get": {
        "tags": [
          "Enrichment"
        ],
        "summary": "Get JIT enrichment job status",
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Job status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrichmentJob"
                }
              }
            }
          },
          "404": {
            "description": "Job not found or not owned by this key"
          }
        }
      }
    },
    "/gdpr/opt-out": {
      "post": {
        "tags": [
          "GDPR"
        ],
        "summary": "GDPR Article 17 \u2014 erasure request (public, no auth required)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "country": {
                    "type": "string"
                  },
                  "reason": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Submitted, applied within 72h"
          }
        },
        "security": []
      }
    },
    "/gdpr/access": {
      "post": {
        "tags": [
          "GDPR"
        ],
        "summary": "GDPR Article 15 \u2014 subject access request (public, email-verified)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "subject_name"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "subject_name": {
                    "type": "string"
                  },
                  "country": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Submitted, data export within 72h after email verification"
          }
        },
        "security": []
      }
    },
    "/status": {
      "get": {
        "tags": [
          "Status"
        ],
        "summary": "Service status + dataset freshness (JSON, public)",
        "responses": {
          "200": {
            "description": "Live status payload",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        },
        "security": []
      }
    },
    "/me": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "API key info + monthly usage",
        "responses": {
          "200": {
            "description": "Plan, limit, used_this_month"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/countries": {
      "get": {
        "tags": [
          "Tenders"
        ],
        "summary": "List supported countries + indexed tender counts",
        "security": [],
        "responses": {
          "200": {
            "description": "Indexed countries"
          }
        }
      }
    },
    "/health": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Health check",
        "security": [],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/companies/search": {
      "get": {
        "tags": [
          "Companies (Norway)"
        ],
        "summary": "Search Norwegian companies by name, orgnr, or NACE",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "orgnr",
            "in": "query",
            "schema": {
              "type": "string",
              "pattern": "^\\d{9}$"
            }
          },
          {
            "name": "nace",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Page"
          }
        ],
        "responses": {
          "200": {
            "description": "Search results from the canonical company graph"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/companies/{orgnr}": {
      "get": {
        "tags": [
          "Companies (Norway)"
        ],
        "summary": "Norwegian company identity",
        "parameters": [
          {
            "$ref": "#/components/parameters/Orgnr"
          }
        ],
        "responses": {
          "200": {
            "description": "Identity, NACE, addresses, status"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/companies/{orgnr}/snapshot": {
      "get": {
        "tags": [
          "Companies (Norway)"
        ],
        "summary": "One-call digest across every data source",
        "parameters": [
          {
            "$ref": "#/components/parameters/Orgnr"
          }
        ],
        "responses": {
          "200": {
            "description": "Identity, accounts, officers, contact, tech, procurement, EU grants, shareholders, sanctions, narrative, with data_completeness score and to_enrich pointers"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/companies/bulk": {
      "post": {
        "tags": [
          "Companies (Norway)"
        ],
        "summary": "Enrich up to 100 Norwegian companies in one call",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "orgnrs"
                ],
                "properties": {
                  "orgnrs": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "pattern": "^\\d{9}$"
                    },
                    "maxItems": 100
                  },
                  "include": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "officers",
                        "accounts"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Profiles per orgnr (counts as N requests against monthly limit)"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/companies/{orgnr}/officers": {
      "get": {
        "tags": [
          "Companies (Norway)"
        ],
        "summary": "Current + historical officers (board, executives, others)",
        "parameters": [
          {
            "$ref": "#/components/parameters/Orgnr"
          }
        ],
        "responses": {
          "200": {
            "description": "Officers grouped by ledelse/styre/andre, with churn signal"
          }
        }
      }
    },
    "/companies/{orgnr}/accounts": {
      "get": {
        "tags": [
          "Companies (Norway)"
        ],
        "summary": "Latest annual accounts with computed ratios",
        "parameters": [
          {
            "$ref": "#/components/parameters/Orgnr"
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "SELSKAP",
                "KONSERN"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Income statement, balance sheet, ratios. Free tier returns latest year only."
          }
        }
      }
    },
    "/companies/{orgnr}/contact": {
      "get": {
        "tags": [
          "Companies (Norway)"
        ],
        "summary": "Verified emails, phones, named key personnel \u2014 4-layer enrichment",
        "description": "Multi-signal contact enrichment with confidence scoring. Returns role-tagged emails (IR, media, press, owner relations), labelled phones, and named executives (CEO, CFO, Chair, head of IR/Media) with full role attribution. Background pipeline upgrades the cache after first request \u2014 initial response is <5s, subsequent requests return the fully-enriched cache in <100ms. Strict filtering rejects historical/former employees, single-name entries, and duplicate exclusive roles. Cached 30 days per company.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Orgnr"
          },
          {
            "name": "refresh",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Force re-crawl (default uses 30-day cache)."
          }
        ],
        "responses": {
          "200": {
            "description": "Verified emails, phones, role-labelled contacts (`labels` map keyed by `email:` or `phone:` to role/department), `named_contacts` array of key personnel (name, role, optional email, optional phone), MX-verified `candidates`. `enrichment_in_progress: true` indicates Layer 4 web-search is still running in background \u2014 refresh in ~30s for the fully-enriched data."
          }
        }
      }
    },
    "/companies/{orgnr}/changes": {
      "get": {
        "tags": [
          "Companies (Norway)"
        ],
        "summary": "Registry change history (audit trail)",
        "parameters": [
          {
            "$ref": "#/components/parameters/Orgnr"
          },
          {
            "name": "since",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Audit trail of registry updates"
          }
        }
      }
    },
    "/companies/{orgnr}/subsidiaries": {
      "get": {
        "tags": [
          "Companies (Norway)"
        ],
        "summary": "Direct subsidiaries (parent \u2192 child)",
        "parameters": [
          {
            "$ref": "#/components/parameters/Orgnr"
          }
        ],
        "responses": {
          "200": {
            "description": "Companies that registered this orgnr as parent. Sparse \u2014 full ownership in /shareholders."
          }
        }
      }
    },
    "/companies/{orgnr}/peer-benchmarks": {
      "get": {
        "tags": [
          "Companies (Norway)"
        ],
        "summary": "Percentile rank vs NACE peer cohort",
        "parameters": [
          {
            "$ref": "#/components/parameters/Orgnr"
          }
        ],
        "responses": {
          "200": {
            "description": "Revenue, margin, ROE, equity-ratio percentiles vs peers in same 2-digit NACE."
          }
        }
      }
    },
    "/companies/{orgnr}/narrative": {
      "get": {
        "tags": [
          "Companies (Norway)"
        ],
        "summary": "AI-generated executive summary",
        "parameters": [
          {
            "$ref": "#/components/parameters/Orgnr"
          }
        ],
        "responses": {
          "200": {
            "description": "One-paragraph narrative from cached profile + accounts + officers"
          }
        }
      }
    },
    "/companies/{orgnr}/tender-velocity": {
      "get": {
        "tags": [
          "Companies (Norway)"
        ],
        "summary": "Monthly tender-publication velocity as buyer (cross-Nordic)",
        "parameters": [
          {
            "name": "orgnr",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^\\d{6,12}$"
            }
          },
          {
            "$ref": "#/components/parameters/Country"
          },
          {
            "name": "name",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Override profile-cache name lookup (use for non-NOR companies)."
          }
        ],
        "responses": {
          "200": {
            "description": "24-month buyer-name match across all 5 countries by default; narrow with ?country="
          }
        }
      }
    },
    "/companies/{orgnr}/contract-wins": {
      "get": {
        "tags": [
          "Awards"
        ],
        "summary": "Public contracts won by a Norwegian company",
        "parameters": [
          {
            "$ref": "#/components/parameters/Orgnr"
          },
          {
            "name": "period",
            "in": "query",
            "schema": {
              "type": "string",
              "pattern": "^\\d+[dwm]$",
              "default": "24m"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Awarded contracts where this orgnr is the winner"
          }
        }
      }
    },
    "/companies/{orgnr}/shareholders": {
      "get": {
        "tags": [
          "Shareholders"
        ],
        "summary": "Shareholders of a Norwegian AS",
        "parameters": [
          {
            "$ref": "#/components/parameters/Orgnr"
          },
          {
            "name": "year",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Defaults to most recent fiscal year cached."
          },
          {
            "name": "min_pct",
            "in": "query",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 100
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Per-shareholder ownership, share count, share class, computed pct."
          }
        }
      }
    },
    "/companies/{orgnr}/tech": {
      "get": {
        "tags": [
          "Tech"
        ],
        "summary": "Detected tech stack (Stripe, WordPress, HubSpot, etc.)",
        "parameters": [
          {
            "$ref": "#/components/parameters/Orgnr"
          }
        ],
        "responses": {
          "200": {
            "description": "Cached fingerprint from website crawl. Call /contact first to populate."
          }
        }
      }
    },
    "/companies/{orgnr}/sanctions-check": {
      "get": {
        "tags": [
          "Sanctions"
        ],
        "summary": "AML check: company name + cached officers vs the global sanctions screen",
        "parameters": [
          {
            "$ref": "#/components/parameters/Orgnr"
          }
        ],
        "responses": {
          "200": {
            "description": "Per-name screening results. Call /officers first to populate the officer list."
          }
        }
      }
    },
    "/companies/{orgnr}/notices": {
      "get": {
        "tags": [
          "Tenders"
        ],
        "summary": "Tenders this Norwegian company has been buyer on",
        "parameters": [
          {
            "$ref": "#/components/parameters/Orgnr"
          }
        ],
        "responses": {
          "200": {
            "description": "Joined tender history"
          }
        }
      }
    },
    "/companies/bankruptcies": {
      "get": {
        "tags": [
          "Companies (Norway)"
        ],
        "summary": "Currently bankrupt Norwegian companies",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Page"
          }
        ],
        "responses": {
          "200": {
            "description": "Registry bankruptcy flag, paginated"
          }
        }
      }
    },
    "/companies/dk/search": {
      "get": {
        "tags": [
          "Companies (Multi-Nordic)"
        ],
        "summary": "Search Danish companies",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "CVR-based identity. Owners available on paid tiers."
          }
        }
      }
    },
    "/companies/dk/{cvr}": {
      "get": {
        "tags": [
          "Companies (Multi-Nordic)"
        ],
        "summary": "Get Danish company by CVR",
        "parameters": [
          {
            "name": "cvr",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "CVR identity + employees + production units"
          }
        }
      }
    },
    "/companies/fi/search": {
      "get": {
        "tags": [
          "Companies (Multi-Nordic)"
        ],
        "summary": "Search Finnish companies",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Y-tunnus-based identity."
          }
        }
      }
    },
    "/companies/fi/{ytunnus}": {
      "get": {
        "tags": [
          "Companies (Multi-Nordic)"
        ],
        "summary": "Get Finnish company by Y-tunnus",
        "parameters": [
          {
            "name": "ytunnus",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Multilingual name history, addresses. Contact data not available for this jurisdiction."
          }
        }
      }
    },
    "/companies/fi/{ytunnus}/financials": {
      "get": {
        "tags": [
          "Companies (Multi-Nordic)"
        ],
        "summary": "List available iXBRL financial periods",
        "parameters": [
          {
            "name": "ytunnus",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Periods with download URLs (raw XBRL, parsing not yet exposed)"
          }
        }
      }
    },
    "/persons/search": {
      "get": {
        "tags": [
          "Persons"
        ],
        "summary": "Fuzzy name search across cached Norwegian officers",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Persons + active role count. Network grows as /companies/{orgnr}/officers is called."
          }
        }
      }
    },
    "/persons/{id}": {
      "get": {
        "tags": [
          "Persons"
        ],
        "summary": "A person's full role history across Norwegian companies",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "All cached board/exec/auditor roles"
          }
        }
      }
    },
    "/persons/{id}/network": {
      "get": {
        "tags": [
          "Persons"
        ],
        "summary": "People sharing boards with this person (1st-degree)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "include_resigned",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Connection graph keyed by shared orgnrs"
          }
        }
      }
    },
    "/companies/{orgnr}/path-to/{other_orgnr}": {
      "get": {
        "tags": [
          "Persons"
        ],
        "summary": "Shortest officer-network path between two Norwegian companies",
        "parameters": [
          {
            "$ref": "#/components/parameters/Orgnr"
          },
          {
            "name": "other_orgnr",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^\\d{9}$"
            }
          },
          {
            "name": "max_hops",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 5,
              "default": 3
            }
          },
          {
            "name": "include_resigned",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "BFS path as alternating company + person nodes, or null if no path within max_hops"
          }
        }
      }
    },
    "/persons/{id}/sanctions-check": {
      "get": {
        "tags": [
          "Sanctions"
        ],
        "summary": "Sanctions screen for a single person",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sanctions matches with confidence scores"
          }
        }
      }
    },
    "/sanctions/screen": {
      "get": {
        "tags": [
          "Sanctions"
        ],
        "summary": "Screen any name against the global sanctions + PEP database",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2
            }
          },
          {
            "name": "min_score",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 50,
              "maximum": 100,
              "default": 60
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Matches with score 60-100. Sources reported dynamically."
          }
        }
      }
    },
    "/shareholders/portfolio": {
      "get": {
        "tags": [
          "Shareholders"
        ],
        "summary": "Reverse-lookup: companies a person/entity owns shares in",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "orgnr",
            "in": "query",
            "schema": {
              "type": "string",
              "pattern": "^\\d{9}$"
            }
          },
          {
            "name": "year",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Holdings list with computed ownership pct"
          }
        }
      }
    },
    "/tech/{technology}/companies": {
      "get": {
        "tags": [
          "Tech"
        ],
        "summary": "Find Norwegian companies using a specific technology",
        "parameters": [
          {
            "name": "technology",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "Stripe"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Companies whose website signals use of this tech"
          }
        }
      }
    },
    "/tenders/search": {
      "get": {
        "tags": [
          "Tenders"
        ],
        "summary": "Search public-procurement notices across the Nordics",
        "description": "Unified search across EU-threshold notices for all 5 Nordic countries plus below-threshold Norwegian municipal and county procurements. Use the `scope` parameter to limit the search.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Country"
          },
          {
            "name": "scope",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "eu",
                "national_no"
              ]
            },
            "description": "Filter by procurement scope. `eu` = EU-threshold notices for all 5 Nordic countries (English titles where available). `national_no` = all Norwegian notices including below-threshold (Norwegian-language titles + descriptions). Omit to search both."
          },
          {
            "name": "buyer_orgnr",
            "in": "query",
            "schema": {
              "type": "string",
              "pattern": "^\\d{9}$"
            },
            "description": "Filter to tenders PUBLISHED BY a specific Norwegian buyer (the public-sector entity issuing the procurement). 9-digit organisation number."
          },
          {
            "name": "winner_orgnr",
            "in": "query",
            "schema": {
              "type": "string",
              "pattern": "^\\d{9}$"
            },
            "description": "Filter to tenders WON BY a specific Norwegian supplier (9-digit organisation number). When set, results come from awarded contracts (not open notices) and include winner details."
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Full-text search query against title and description. Language-agnostic tokenizer matches both Norwegian and English titles."
          },
          {
            "name": "cpv",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "CPV (Common Procurement Vocabulary) code. Coverage strongest on EU-scope notices."
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Page"
          }
        ],
        "responses": {
          "200": {
            "description": "Tender notices sorted by publication date desc. Each result includes a `scope` field (`eu` or `national_no`)."
          }
        }
      }
    },
    "/tenders/{id}": {
      "get": {
        "tags": [
          "Tenders"
        ],
        "summary": "Get a single tender notice",
        "description": "Fetches a notice by ID. Accepts EU-scope publication numbers (format: number-year, e.g. \"317565-2026\") and national Norwegian notice IDs (format: year-number, e.g. \"2026-108414\"). Response includes a `scope` field identifying the procurement scope.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]+-[0-9]+$"
            },
            "description": "EU-scope: \"317565-2026\". National-NO: \"2026-108414\"."
          }
        ],
        "responses": {
          "200": {
            "description": "Full notice payload"
          }
        }
      }
    },
    "/tenders/leaderboard": {
      "get": {
        "tags": [
          "Tenders"
        ],
        "summary": "Top public-sector buyers by tender volume",
        "parameters": [
          {
            "$ref": "#/components/parameters/Country"
          },
          {
            "name": "cpv",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "period",
            "in": "query",
            "schema": {
              "type": "string",
              "pattern": "^\\d+[dwm]$",
              "default": "12m"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Buyer-rank by notice count + total value"
          }
        }
      }
    },
    "/awards/search": {
      "get": {
        "tags": [
          "Awards"
        ],
        "summary": "Search awarded public-procurement contracts",
        "parameters": [
          {
            "$ref": "#/components/parameters/Country"
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cpv",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "min_value",
            "in": "query",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "winner_orgnr",
            "in": "query",
            "schema": {
              "type": "string",
              "pattern": "^\\d{9}$"
            }
          },
          {
            "name": "winner_name",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "buyer_name",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Page"
          }
        ],
        "responses": {
          "200": {
            "description": "Awarded contracts with winner + buyer + value + CPV"
          }
        }
      }
    },
    "/awards/leaderboard": {
      "get": {
        "tags": [
          "Awards"
        ],
        "summary": "Top contract-winning suppliers",
        "parameters": [
          {
            "$ref": "#/components/parameters/Country"
          },
          {
            "name": "period",
            "in": "query",
            "schema": {
              "type": "string",
              "pattern": "^\\d+[dwm]$",
              "default": "12m"
            }
          },
          {
            "name": "cpv",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Suppliers ranked by contracts won + total value"
          }
        }
      }
    },
    "/signup": {
      "post": {
        "tags": [
          "Account"
        ],
        "summary": "Start signup \u2014 emails verification code",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "plan": {
                    "type": "string",
                    "enum": [
                      "free",
                      "pro",
                      "business"
                    ],
                    "default": "free"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification email dispatched"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/signup/verify": {
      "post": {
        "tags": [
          "Account"
        ],
        "summary": "Complete signup \u2014 issue API key",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "code"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "code": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "api_key (returned ONCE \u2014 store securely)"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/agent/plans": {
      "get": {
        "tags": [
          "Agent buying"
        ],
        "summary": "List available plans + prices for autonomous buying",
        "description": "Public, unauthenticated. Designed for AI agents to discover what they can buy before calling /agent/subscribe. Returns plan IDs, monthly EUR prices, monthly request limits, and the corresponding purchase channel.",
        "security": [],
        "responses": {
          "200": {
            "description": "Array of plans with pricing + tax + payment guidance"
          }
        }
      }
    },
    "/agent/subscribe": {
      "post": {
        "tags": [
          "Agent buying"
        ],
        "summary": "Subscribe to a paid plan with a Stripe payment method \u2014 returns API key in response",
        "description": "Public, unauthenticated. Designed for AI agents to subscribe end-to-end in a single API call: provide email, plan, country, and a Stripe PaymentMethod ID (pm_xxx). Server attaches the card to a customer, creates a subscription with auto-charge, and returns a working API key in the response body. No browser, no Customer Portal, no email round-trip. If a free key already exists for this email, it is upgraded in place. If a paid subscription already exists, the request is rejected with 409 \u2014 use /agent/change-plan with X-API-Key instead.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "plan",
                  "payment_method",
                  "country"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Owner email. Must be unique among active paid subscriptions."
                  },
                  "plan": {
                    "type": "string",
                    "enum": [
                      "starter",
                      "builder",
                      "pro",
                      "business"
                    ],
                    "description": "Plan ID. See GET /agent/plans for prices and limits."
                  },
                  "payment_method": {
                    "type": "string",
                    "pattern": "^pm_",
                    "description": "Stripe PaymentMethod ID. In test mode, pm_card_visa works."
                  },
                  "country": {
                    "type": "string",
                    "pattern": "^[A-Z]{2}$",
                    "description": "ISO 3166-1 alpha-2 billing country (e.g. NO, SE, DE, US). Required for MVA / VAT calculation."
                  },
                  "agent_name": {
                    "type": "string",
                    "maxLength": 80,
                    "description": "Optional free-text label stored on the API key and Stripe customer for your bookkeeping."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Subscription active. Body contains api_key (shown ONCE \u2014 store it), plan, monthly_limit, subscription_id, customer_id, next_renewal."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "402": {
            "description": "Card declined or payment requires additional auth (e.g. 3DS). Body includes Stripe code and subscription_id when applicable."
          },
          "409": {
            "description": "An active paid subscription already exists for this email. Use POST /agent/change-plan with the existing X-API-Key."
          },
          "503": {
            "description": "Stripe not configured on server."
          }
        }
      }
    },
    "/agent/change-plan": {
      "post": {
        "tags": [
          "Agent buying"
        ],
        "summary": "Upgrade or downgrade an active subscription in place \u2014 authenticated by API key",
        "description": "Authenticated with X-API-Key. Updates the existing Stripe subscription to a new plan with prorated billing. The API key is unchanged \u2014 agents continue using the same key after the plan change. Only plan and monthly_limit on /me reflect the new tier.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "plan"
                ],
                "properties": {
                  "plan": {
                    "type": "string",
                    "enum": [
                      "starter",
                      "builder",
                      "pro",
                      "business"
                    ],
                    "description": "Target plan ID."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Plan changed. Body includes new plan, monthly_limit, subscription_id, next_renewal, and a human-readable message."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "503": {
            "description": "Stripe not configured on server."
          }
        }
      }
    },
    "/subscriptions": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Create a webhook subscription",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "webhook_url"
                ],
                "properties": {
                  "webhook_url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "event_type": {
                    "type": "string",
                    "enum": [
                      "tender.published",
                      "sanctions.added",
                      "company.bankruptcy",
                      "company.officer_change"
                    ],
                    "default": "tender.published"
                  },
                  "filter": {
                    "type": "object",
                    "description": "Per-event filter object. See /openapi.json or POST response notes for keys."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Subscription with signing_secret (returned ONCE)"
          }
        }
      },
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "List your subscriptions",
        "responses": {
          "200": {
            "description": "Per-key subscription list"
          }
        }
      }
    },
    "/subscriptions/{id}": {
      "delete": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Delete a subscription",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "deleted: 1"
          }
        }
      }
    },
    "/companies/us/list": {
      "get": {
        "tags": [
          "Companies (US)"
        ],
        "summary": "Filter US businesses by industry, state, and employee count",
        "description": "Returns a list of verified active US businesses matching the filter. Every result is a real business with a verifiable payroll history. Filter by NAICS code (e.g. 511210 = software publishers, 5418 = advertising), US state (2-letter), city, and employee range.",
        "parameters": [
          {
            "name": "naics",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "6-digit NAICS code, e.g. 511210 (Software Publishers). Comma-separate multiple."
          },
          {
            "name": "naics_prefix",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "2-5 digit NAICS prefix for broader categories, e.g. \"5112\" (Software)."
          },
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "US 2-letter state postal code, e.g. CA, TX, NY."
          },
          {
            "name": "city",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_employees",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "max_employees",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "name_like",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Fuzzy name match (trigram)."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of matching US businesses"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/companies/us/smb/{id}": {
      "get": {
        "tags": [
          "Companies (US)"
        ],
        "summary": "Single US business by id",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Stable id returned by /companies/us/list (40-char hex)."
          }
        ],
        "responses": {
          "200": {
            "description": "Full record"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/companies/us/smb/{id}/enrich": {
      "get": {
        "tags": [
          "Lead enrichment"
        ],
        "summary": "Full lead enrichment for a US business",
        "description": "Auto-discovers the company\u2019s website, then extracts: company description, tech stack, email provider (Google Workspace / Microsoft 365 / Zoho / etc.), social URLs (LinkedIn / Twitter / GitHub), public emails (with labels), phone numbers (with labels), and named executives where available. Takes 30\u201360s per call.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Enriched lead"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/enrich/all": {
      "get": {
        "tags": [
          "Lead enrichment"
        ],
        "summary": "Domain-first composite enrichment",
        "description": "Pass any website URL and get back identity match (Nordic registry, US public-company match, or US SMB match) + tech stack + sanctions screen + contacts + email provider + social URLs + optional AI narrative. Works globally.",
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Website domain, e.g. cognite.com"
          },
          {
            "name": "country",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "NO",
                "SE",
                "US"
              ]
            },
            "description": "Hint for phone-format parsing and prompt language. Default NO."
          },
          {
            "name": "narrative",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": true
            },
            "description": "Set to false to skip the AI narrative and save credits."
          }
        ],
        "responses": {
          "200": {
            "description": "Composite enrichment"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/enrich/contacts": {
      "get": {
        "tags": [
          "Lead enrichment"
        ],
        "summary": "Contact-only enrichment for a domain",
        "description": "Pass any website URL and get back emails (with labels), phones (with labels), and named executives when available. Used standalone or as a step in a larger workflow.",
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "company",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Company name hint to improve extraction accuracy."
          },
          {
            "name": "country",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "NO",
                "SE",
                "US"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Contacts payload"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/enrich/by-name": {
      "get": {
        "tags": [
          "Lead enrichment"
        ],
        "summary": "Name-first enrichment (no domain needed)",
        "description": "Pass a company name (and optional city / state / country) and we auto-discover the website, then run the full enrichment pipeline. Useful for CRM data where domain isn\u2019t known.",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "city",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "US state 2-letter or Nordic city/region."
          },
          {
            "name": "country",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "NO",
                "SE",
                "US"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Discovery + enrichment"
          }
        }
      }
    },
    "/contacts/discover": {
      "get": {
        "tags": [
          "Contact discovery"
        ],
        "summary": "Sales-shaped contact discovery",
        "description": "The endpoint a sales rep actually wants: filter by plain-English industry + role + region + company size, get back a flat list of named decision-makers with email + phone + company context. When small SMBs don\u2019t publish executives, falls back to a company general-inbox contact so you always get something usable. Each call enriches up to 25 companies; ~30\u201360s end-to-end.",
        "parameters": [
          {
            "name": "industry",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Plain-English industry: software, saas, fintech, finance, healthcare, biotech, marketing, advertising, consulting, real_estate, retail, ecommerce, manufacturing, construction, education, legal, accounting, media, logistics, food, restaurant, energy, agriculture, hr, recruiting. Or pass a NAICS code/prefix."
          },
          {
            "name": "role",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Optional role bucket: ceo, founder, cto, cfo, coo, cmo, cro, cpo, cio, chro, vp, director, sales, marketing, engineering, product, finance, hr, operations."
          },
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "US 2-letter state code."
          },
          {
            "name": "min_employees",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "max_employees",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "maximum": 50,
              "default": 25
            },
            "description": "Max contacts returned."
          },
          {
            "name": "enrich_companies",
            "in": "query",
            "schema": {
              "type": "integer",
              "maximum": 25,
              "default": 12
            },
            "description": "Max companies to enrich per call (each ~5\u201330s)."
          }
        ],
        "responses": {
          "200": {
            "description": "Flat contacts list with named_count, general_count, and an optional hint"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/dashboard": {
      "get": {
        "tags": [
          "Status"
        ],
        "summary": "Customer dashboard (usage, plan, webhooks, recent deliveries)",
        "description": "Backing data for /dashboard.html: monthly usage, plan + limit, top endpoints (30d), webhook subscriptions, recent webhook deliveries (last 30), and 7-day delivery status rollup.",
        "responses": {
          "200": {
            "description": "Dashboard payload",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "key_label": {
                      "type": "string",
                      "nullable": true
                    },
                    "plan": {
                      "type": "string"
                    },
                    "monthly_limit": {
                      "type": "integer"
                    },
                    "used_this_month": {
                      "type": "integer"
                    },
                    "remaining": {
                      "type": "integer"
                    },
                    "top_endpoints_30d": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "endpoint": {
                            "type": "string"
                          },
                          "hits": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "webhooks": {
                      "type": "array"
                    },
                    "recent_deliveries": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "subscription_id": {
                            "type": "integer"
                          },
                          "event_type": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "delivered",
                              "failed",
                              "pending",
                              "dead"
                            ]
                          },
                          "attempts": {
                            "type": "integer"
                          },
                          "last_response_code": {
                            "type": "integer",
                            "nullable": true
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "delivered_at": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true
                          },
                          "next_retry_at": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true
                          },
                          "webhook_url": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "delivery_stats_7d": {
                      "type": "object",
                      "properties": {
                        "delivered": {
                          "type": "integer"
                        },
                        "failed": {
                          "type": "integer"
                        },
                        "pending": {
                          "type": "integer"
                        },
                        "dead": {
                          "type": "integer"
                        }
                      }
                    },
                    "features": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/billing/portal": {
      "post": {
        "tags": [
          "Account"
        ],
        "summary": "Create a Stripe customer-portal session",
        "description": "Returns a one-time URL the customer visits to manage their subscription (update card, view invoices, change plan, cancel). Server-side lookup by email - no API key required.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Portal URL",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "portal_url": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Email missing"
          },
          "404": {
            "description": "No active subscription for that email"
          },
          "502": {
            "description": "Stripe error"
          },
          "503": {
            "description": "Stripe not configured"
          }
        }
      }
    },
    "/me/keys": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "List all API keys for the authenticated owner",
        "description": "Returns up to 50 keys belonging to the same owner_email. The current key is flagged. Returns key_prefix (not full key) for security.",
        "responses": {
          "200": {
            "description": "Key list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "owner_email": {
                      "type": "string"
                    },
                    "current_key_id": {
                      "type": "integer"
                    },
                    "keys": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "key_prefix": {
                            "type": "string"
                          },
                          "label": {
                            "type": "string",
                            "nullable": true
                          },
                          "plan": {
                            "type": "string"
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "revoked_at": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true
                          },
                          "is_current": {
                            "type": "boolean"
                          },
                          "is_active": {
                            "type": "boolean"
                          },
                          "last_used_at": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true,
                            "description": "When this key was last used to authenticate a request. NULL if never used."
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Authenticated key has no owner_email"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "tags": [
          "Account"
        ],
        "summary": "Create a new API key (inherits plan + limit from caller)",
        "description": "Issues a new key under the same owner_email. Useful for: rotating credentials, separating environments (prod/staging), per-team keys. Max 5 active keys per email. The full key is only returned ONCE.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "label": {
                    "type": "string",
                    "maxLength": 80
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "New key created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": "integer"
                    },
                    "api_key": {
                      "type": "string",
                      "description": "Only returned this once. Store immediately."
                    },
                    "key_prefix": {
                      "type": "string"
                    },
                    "label": {
                      "type": "string",
                      "nullable": true
                    },
                    "plan": {
                      "type": "string"
                    },
                    "monthly_limit": {
                      "type": "integer"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Authenticated key has no owner_email"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "Too many active keys (max 5)"
          }
        }
      }
    },
    "/me/keys/{id}": {
      "delete": {
        "tags": [
          "Account"
        ],
        "summary": "Revoke a specific API key",
        "description": "Marks the key revoked. Cannot revoke the key used to authenticate this request - use POST /me/rotate-key instead, which issues a new key first.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "revoked_id": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Key not found or already revoked"
          },
          "409": {
            "description": "Cannot revoke the currently-authenticating key (use POST /me/rotate-key)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/me/rotate-key": {
      "post": {
        "tags": [
          "Account"
        ],
        "summary": "Safely rotate the current API key",
        "description": "Issues a new key inheriting plan + limit. The OLD key remains active so clients have time to migrate. After updating clients, call DELETE /me/keys/{old_id} to revoke. The full new key is only returned ONCE.",
        "responses": {
          "200": {
            "description": "Rotated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "new_id": {
                      "type": "integer"
                    },
                    "new_api_key": {
                      "type": "string"
                    },
                    "new_key_prefix": {
                      "type": "string"
                    },
                    "old_id": {
                      "type": "integer"
                    },
                    "old_key_prefix": {
                      "type": "string",
                      "nullable": true
                    },
                    "plan": {
                      "type": "string"
                    },
                    "monthly_limit": {
                      "type": "integer"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Authenticated key has no owner_email"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/webhooks/{id}/test": {
      "post": {
        "tags": [
          "Account"
        ],
        "summary": "Fire a sample event to verify a webhook subscription works",
        "description": "Sends a synthetic event matching the subscription's event_type to the subscriber's webhook_url. The payload includes \"_test\": true so receivers can distinguish from production events. The response includes the delivery row \u2014 check delivery.status to confirm receipt. If status=failed, the retry worker handles backoff (1m \u2192 5m \u2192 15m \u2192 1h \u2192 6h, then dead-letter).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Webhook subscription id (from POST /webhooks response)."
          }
        ],
        "responses": {
          "200": {
            "description": "Test event fired",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "subscription_id": {
                      "type": "integer"
                    },
                    "webhook_url": {
                      "type": "string"
                    },
                    "event_type": {
                      "type": "string"
                    },
                    "payload_sent": {
                      "type": "object",
                      "description": "The synthetic payload that was POSTed to your URL. Includes _test: true marker."
                    },
                    "delivery": {
                      "type": "object",
                      "nullable": true,
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "delivered",
                            "failed",
                            "pending",
                            "dead"
                          ]
                        },
                        "attempts": {
                          "type": "integer"
                        },
                        "last_response_code": {
                          "type": "integer",
                          "nullable": true
                        },
                        "last_response_body": {
                          "type": "string",
                          "nullable": true
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "delivered_at": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true
                        },
                        "next_retry_at": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true
                        }
                      }
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid subscription id"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Subscription belongs to a different api key"
          },
          "404": {
            "description": "Subscription not found"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Your Nordic Data API key. Free tier: 100/mo at https://nordicdata.cloud. Sandbox: sandbox_try_2026 (30/hr, no signup)."
      },
      "AdminToken": {
        "type": "apiKey",
        "in": "header",
        "name": "x-admin-token"
      }
    },
    "parameters": {
      "CanonicalId": {
        "name": "canonical_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "8b0a130f-e6e9-4ed6-97f3-8ebbe06dfac3",
        "description": "Canonical company UUID. Use /v2/companies/search or /resolve to find one."
      },
      "Orgnr": {
        "name": "orgnr",
        "in": "path",
        "required": true,
        "description": "9-digit Norwegian organisation number.",
        "schema": {
          "type": "string",
          "pattern": "^\\d{9}$"
        }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 1000,
          "default": 50
        }
      },
      "Page": {
        "name": "page",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        }
      },
      "Country": {
        "name": "country",
        "in": "query",
        "schema": {
          "type": "string",
          "enum": [
            "NOR",
            "SWE",
            "DNK",
            "FIN",
            "ISL"
          ]
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid X-API-Key",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "error": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Monthly limit reached",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "BadRequest": {
        "description": "Invalid input",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Company": {
        "type": "object",
        "properties": {
          "canonical_id": {
            "type": "string",
            "format": "uuid"
          },
          "country": {
            "type": "string"
          },
          "registry_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "legal_form": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "example": "active"
          }
        }
      },
      "CanonicalCompany": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Company"
          },
          {
            "type": "object",
            "properties": {
              "registered_at": {
                "type": "string",
                "format": "date",
                "nullable": true
              },
              "dissolved_at": {
                "type": "string",
                "format": "date",
                "nullable": true
              },
              "parent_canonical_id": {
                "type": "string",
                "format": "uuid",
                "nullable": true
              },
              "facts": {
                "type": "object",
                "description": "Map of fact_type \u2192 value (latest)"
              },
              "_provenance": {
                "type": "object",
                "description": "Map of fact_type \u2192 { source, confidence, fetched_at }"
              }
            }
          }
        ]
      },
      "Fact": {
        "type": "object",
        "properties": {
          "fact_type": {
            "type": "string",
            "example": "address"
          },
          "value": {
            "type": "object",
            "additionalProperties": true
          },
          "source": {
            "type": "string",
            "example": "registry"
          },
          "confidence": {
            "type": "number",
            "example": 1.0
          },
          "fetched_at": {
            "type": "string",
            "format": "date-time"
          },
          "verified_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "SearchResults": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "results": {
            "type": "array",
            "items": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/Company"
                },
                {
                  "type": "object",
                  "properties": {
                    "score": {
                      "type": "number"
                    },
                    "match_type": {
                      "type": "string",
                      "enum": [
                        "prefix",
                        "fuzzy"
                      ]
                    }
                  }
                }
              ]
            }
          }
        }
      },
      "ContactsResponse": {
        "type": "object",
        "properties": {
          "canonical_id": {
            "type": "string"
          },
          "tier_a_count": {
            "type": "integer",
            "description": "Emails with composite_confidence >= 0.8"
          },
          "tier_b_count": {
            "type": "integer",
            "description": "0.5 <= confidence < 0.8"
          },
          "tier_c_count": {
            "type": "integer",
            "description": "Confidence < 0.5"
          },
          "emails": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "email": {
                  "type": "string"
                },
                "confidence": {
                  "type": "number"
                },
                "is_role_alias": {
                  "type": "boolean"
                },
                "person_id": {
                  "type": "integer",
                  "nullable": true
                },
                "candidate_persons": {
                  "type": "array",
                  "nullable": true
                },
                "signals": {
                  "type": "object"
                },
                "seen_on_urls": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "phones": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "phone": {
                  "type": "string"
                },
                "source": {
                  "type": "string"
                },
                "last_verified_at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          }
        }
      },
      "GlobalOfficers": {
        "type": "object",
        "properties": {
          "canonical_id": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "officers_with_overlap": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "officer": {
                  "type": "string"
                },
                "born": {
                  "type": "integer",
                  "nullable": true
                },
                "also_directs": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "orgnr": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      }
                    }
                  }
                },
                "count": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "SanctionsMatches": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string"
          },
          "matches": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "source": {
                  "type": "string"
                },
                "entity_type": {
                  "type": "string"
                },
                "program": {
                  "type": "string"
                },
                "score": {
                  "type": "number"
                },
                "ingested_at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          }
        }
      },
      "EnrichmentJob": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "canonical_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "completed",
              "failed"
            ]
          },
          "result": {
            "type": "object",
            "nullable": true,
            "properties": {
              "domain": {
                "type": "string",
                "nullable": true
              },
              "discovered_domain": {
                "type": "boolean"
              },
              "emails": {
                "type": "integer"
              },
              "phones": {
                "type": "integer"
              },
              "mx_ok": {
                "type": "boolean"
              }
            }
          },
          "error": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "started_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "Status": {
        "type": "object",
        "properties": {
          "service": {
            "type": "string",
            "example": "nordicdata.cloud"
          },
          "status": {
            "type": "string",
            "example": "operational"
          },
          "version": {
            "type": "string",
            "example": "0.5.0"
          },
          "canonical_companies": {
            "type": "integer"
          },
          "sanctions_entities": {
            "type": "integer"
          },
          "company_facts": {
            "type": "integer"
          },
          "verified_emails": {
            "type": "integer"
          },
          "verified_phones": {
            "type": "integer"
          },
          "company_domains_live": {
            "type": "integer"
          },
          "database_size": {
            "type": "string"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        }
      }
    }
  }
}