{
  "openapi": "3.1.0",
  "info": {
    "title": "OpenMercantil API",
    "version": "1.9.3",
    "summary": "Versioned public-read, browser-account, billing, support and provider-callback contracts.",
    "description": "Public JSON API for Spanish company information derived from BORME and other public sources. OpenMercantil is an independent informational service; it is NOT the BOE, BORME or Registro Mercantil and does NOT replace official certificates or registry extracts.\n\n**Rate limits.** Free: 60 req/min y 200 req/día por IP. Planes superiores (Profesional 5.000 req/día, MAX 50.000 req/día, Enterprise 500.000+ req/día) según cuenta y API key. Cabeceras `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, `X-OpenMercantil-Plan`, `Retry-After`.\n\n**License and attribution.** Source-specific metadata in each response and the active versioned source catalog prevails. OpenMercantil does not relicense upstream content under a blanket license. Unknown, review and restricted datasets are omitted or return `503 legal_layer_unavailable`. BOE/BORME material is re-used under Ley 37/2007 and its official version remains boe.es. Court judgments are not exposed; CENDOJ remains citation-index only under CGPJ Reglamento 3/2010.\n\n**Machine-readable catalog (DCAT-AP-ES):** https://openmercantil.es/catalog.rdf",
    "termsOfService": "https://openmercantil.es/terminos-de-uso",
    "contact": {
      "name": "OpenMercantil",
      "url": "https://openmercantil.es/soporte",
      "email": "social@openmercantil.es"
    },
    "license": {
      "name": "Source-specific upstream terms; see response catalog metadata",
      "url": "https://openmercantil.es/terminos-de-uso"
    },
    "x-publisher": {
      "name": "OpenMercantil",
      "url": "https://openmercantil.es/",
      "email": "social@openmercantil.es"
    },
    "x-spatial": "http://publications.europa.eu/resource/authority/country/ESP",
    "x-temporal": "2009-01-01/..",
    "x-language": "es",
    "x-dcat-catalog": "https://openmercantil.es/catalog.rdf",
    "x-rate-limit": {
      "free":         { "per_min": 60,   "per_day": 200,     "kind": "anonymous-ip" },
      "profesional":  { "per_min": 120,  "per_day": 5000,    "kind": "api-key" },
      "max":          { "per_min": 600,  "per_day": 50000,   "kind": "api-key" },
      "enterprise":   { "per_min": 1200, "per_day": 500000,  "kind": "contract" }
    },
    "x-methodology": "https://openmercantil.es/metodologia",
    "x-sources": "https://openmercantil.es/fuentes",
    "x-corrections": "https://openmercantil.es/correcciones",
    "x-contract-status": "Public read, browser-account and provider-callback surfaces are explicitly separated in this contract. Operator/admin routes are excluded. The public MCP consumes only the allowlisted GET read plane.",
    "x-account-segment-contract": {
      "projection": "company_public_v2 immutable corporate sidecar",
      "synchronous_row_cap": 500,
      "bounded_count_cap": 50001,
      "count_semantics": "The segment run response count is the number of rows returned, never a global total. Dataset preview uses total_is_lower_bound=true and total_lower_bound when the bounded count reaches 50001.",
      "related_web_dataset_surface": {
        "preview_path": "/mi-cuenta/datasets/preview",
        "export_path": "/mi-cuenta/datasets/export.csv",
        "synchronous_export_max_rows": 500,
        "overflow_status": 503,
        "overflow_error": "async_export_required"
      }
    },
    "x-company-identity-contract": {
      "version": "1.0",
      "projection": "company_public_v2 immutable generation-bound corporate sidecar",
      "applies_to": "Every /api/v1/company/{slug}*, /api/v1/empresa/{slug}* and /api/v1/grafo/{slug} read before any report, cache, graph or dataset lookup. /api/v1/companies/compare resolves both requested subjects in one bounded company_public_v2 batch before either row is exposed; MCP company tools inherit these preflights through REST.",
      "resolution": {
        "published": "canonical corporate slug admitted",
        "safe_alias": "internally canonicalized and Content-Location emitted",
        "withheld": "neutral 404; includes absent, personal and ambiguous/quarantined identities",
        "unavailable": "503 with no-store; clients must not infer absence"
      },
      "search": "Exact corporate CIF, exact canonical/safe-alias slug, or bounded name_prefix2 pool scored in application code. DNI/NIE and ambiguous CIFs return zero items.",
      "public_company_count": "company_public_projection_state.row_count"
    }
  },
  "externalDocs": {
    "description": "Documentación narrativa con ejemplos en curl/Python/JavaScript",
    "url": "https://openmercantil.es/api/documentacion"
  },
  "servers": [
    {
      "url": "https://openmercantil.es",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Search",
      "description": "Company and person search endpoints"
    },
    {
      "name": "Companies",
      "description": "Company reports and registry events"
    },
    {
      "name": "Persons",
      "description": "Documentary mentions of natural persons in BORME (officer roles). Persons treated as documentary mentions only — no DNI, no contact data, no scoring."
    },
    {
      "name": "Sectors",
      "description": "CNAE sector aggregates, ratios and company listings"
    },
    {
      "name": "BORME",
      "description": "Daily BORME publications, multi-source timeline and registry events"
    },
    {
      "name": "Public Procurement",
      "description": "Public procurement awards (PLACSP) and grants (BDNS)"
    },
    {
      "name": "Risk Signals",
      "description": "Documentary risk signals from public sources (AEPD, CNMC, concursos, AEAT moroso, CENDOJ)"
    },
    {
      "name": "Graph",
      "description": "Corporate and person-to-company relationship graphs. Every emitted record retains the source-specific terms authorized by the active public source catalog; no blanket relicensing applies."
    },
    {
      "name": "Datasets",
      "description": "Bulk exports (CSV / JSON / aggregated stats)"
    },
    {
      "name": "Sources",
      "description": "Source catalog metadata, freshness and integration status"
    },
    {
      "name": "Integrations",
      "description": "Public read-only connector catalog. Never exposes credentials, OAuth tokens, webhook secrets or operator actions."
    },
    {
      "name": "System",
      "description": "Service health and metadata"
    },
    {
      "name": "User",
      "description": "Authenticated Panel Pro endpoints — segments, lists, notes, tags, exports, audit. Requires session cookie (browser) and X-CSRF-Token header for mutations."
    },
    {
      "name": "Billing",
      "description": "Session-bound Stripe checkout, invoices and portal contracts. External actions are bounded, idempotent and never exposed through the public MCP."
    },
    {
      "name": "Support",
      "description": "Customer-support writes. Anonymous creation requires explicit privacy consent; replies require an authenticated owner session and CSRF. Ticket data is never exposed through the public MCP."
    },
    {
      "name": "Legal",
      "description": "Spanish mercantile-law layer (derecho mercantil): legislation corpus + article texts + act→norm bridge. Distributes the consolidated BOE legal corpus structured by OpenMercantil so LLMs and agents can cite it as a source. License: consolidated text from the BOE, reused under Ley 37/2007 (re-use of public sector information); the official version is always boe.es. Informational only — NOT legal advice. Court judgments are NOT exposed here (CENDOJ is kept as a citation-index only, per CGPJ Reglamento 3/2010); this layer distributes legislation + the act↔norm index."
    }
  ],
  "paths": {
    "/api/v1/search": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getSearch",
        "x-query-contract": {"allowed":["q","limit","offset"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"},
        "tags": ["Search"],
        "summary": "Search published Spanish legal entities",
        "description": "Corporate-only search over the immutable company_public_v2 projection. It resolves an exact corporate CIF, an exact canonical/safe-alias slug, or a bounded name-prefix pool. DNI/NIE, malformed identifier-shaped input and ambiguous/quarantined CIFs return zero items; there is no raw companies/search_idx or disk-index fallback.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 120,
              "example": "mercadona"
            },
            "description": "Search query: company name, alias or CIF."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "description": "Maximum number of results."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 1000,
              "default": 0
            },
            "description": "Bounded pagination offset. Values above 1000 fail with 422; future deep pagination requires a generation-bound cursor."
          },
          {"$ref": "#/components/parameters/IfNoneMatchHeader"}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "Search results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResponse"
                }
              }
            }
          },
          "304": {"description": "The admitted corporate search projection and exact normalized query have not changed."},
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "422": {"$ref": "#/components/responses/ValidationFailed"},
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getCompanyBySlug",
        "tags": ["Companies"],
        "summary": "Get a company report",
        "description": "Return the structured company report only after company_public_v2 admits a corporate identity. A safe historical alias is resolved internally and reported through Content-Location; absent, personal or quarantined identities are neutral 404 responses and projection unavailability is 503.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "mercadona-sa"
            },
            "description": "Company slug."
          },
          {"$ref": "#/components/parameters/IfNoneMatchHeader"}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "Content-Location": {"$ref": "#/components/headers/CompanyContentLocation"}
            },
            "description": "Company report",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyReport"
                }
              }
            }
          },
          "304": {"description": "The admitted, attested company report has not changed."},
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/companies/compare": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "x-company-identity-contract": {
          "projection": "company_compare_v1",
          "subject_projection": "company_public_v2",
          "cardinality": 2,
          "admission": "one bounded batch admission for both requested slugs before either company is exposed",
          "canonical_order": "lexicographic by canonical slug; requested_slugs, canonical_slugs and companies remain index-aligned",
          "withheld": "neutral 404 with no partial company",
          "unavailable": "503 no-store; never reinterpret as absence"
        },
        "operationId": "compareCompanies",
        "x-query-contract": {"allowed":["slugs"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter"},
        "tags": ["Companies"],
        "summary": "Compare exactly two admitted companies",
        "description": "Returns only the stable company_compare_v1 projection. Both slugs are resolved together against the immutable company_public_v2 sidecar; safe aliases are canonicalized without redirects. The response excludes reports, blobs, officers, account data, scores and inferred relationships.",
        "parameters": [
          {
            "name": "slugs",
            "in": "query",
            "required": true,
            "style": "form",
            "explode": false,
            "description": "Exactly two distinct corporate slugs serialized as slugs=empresa-a,empresa-b.",
            "schema": {
              "type": "array",
              "minItems": 2,
              "maxItems": 2,
              "uniqueItems": true,
              "items": {
                "type": "string",
                "minLength": 1,
                "maxLength": 240,
                "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
              }
            }
          },
          {"$ref": "#/components/parameters/IfNoneMatchHeader"}
        ],
        "responses": {
          "200": {
            "description": "Two admitted companies in stable canonical order",
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "Content-Location": {"$ref": "#/components/headers/CompanyCompareContentLocation"},
              "ETag": {"$ref": "#/components/headers/EntityTag"}
            },
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/CompanyCompareResponse"}
              }
            }
          },
          "304": {
            "description": "The generation-bound comparison has not changed",
            "headers": {
              "Content-Location": {"$ref": "#/components/headers/CompanyCompareContentLocation"},
              "ETag": {"$ref": "#/components/headers/EntityTag"}
            }
          },
          "400": {
            "description": "Malformed pair or both inputs resolve to the same company",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/CompanyCompareInvalidRequest"}
              }
            }
          },
          "404": {
            "description": "At least one subject is absent, personal, ambiguous, quarantined or legally withheld",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/CompanyCompareNotFound"}
              }
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {
            "description": "The immutable company comparison projection or its authority is unavailable",
            "headers": {
              "Cache-Control": {
                "description": "Projection outages are never cacheable.",
                "schema": {"type": "string", "const": "no-store"}
              },
              "Retry-After": {
                "description": "Seconds to wait before a bounded retry.",
                "schema": {"type": "integer", "minimum": 1}
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {"$ref": "#/components/schemas/ProjectionUnavailableError"},
                    {"$ref": "#/components/schemas/CompanyCompareLegalUnavailable"}
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/datasets/public": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "listPublicCompanyDownloads",
        "parameters": [{"$ref": "#/components/parameters/IfNoneMatchHeader"}],
        "tags": ["Datasets", "Companies"],
        "summary": "List generation-bound public company downloads",
        "description": "Lists exactly the three bounded public company downloads admitted by company_public artifact contract 1.1. Every member is reverified through the immutable manifest and SHA-256 ledger before this atomic catalog is emitted. A missing, stale or tampered member makes the whole projection unavailable; raw company tables, local paths and legacy docroot fallbacks are never exposed.",
        "responses": {
          "200": {
            "description": "Atomic catalog of the three admitted public company downloads",
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "ETag": {"$ref": "#/components/headers/EntityTag"}
            },
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/PublicCompanyDownloadCatalog"}
              }
            }
          },
          "304": {
            "description": "The generation-bound download catalog has not changed",
            "headers": {
              "ETag": {"$ref": "#/components/headers/EntityTag"}
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/events": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getCompanyBySlugEvents",
        "tags": ["Companies", "BORME"],
        "summary": "Get paginated company events",
        "description": "Return BORME events for a known company slug, optionally filtered by calendar year. The closed scalar query contract rejects unknown names, arrays and malformed integer values with 400; valid integers outside their bounds return 422. If year is omitted, the server freezes the current UTC year for the request. Historical coverage starts at 1900 and year must be less than or equal to the current UTC year; there is no fixed calendar ceiling.",
        "x-query-contract": {"allowed":["year","page","page_size"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"},
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "mercadona-sa"
            }
          },
          {
            "name": "year",
            "in": "query",
            "required": false,
            "description": "Calendar year from 1900 through the current UTC year (year <= current UTC year). Defaults dynamically to the current UTC year.",
            "schema": {
              "type": "integer",
              "minimum": 1900,
              "x-maximum-dynamic": "current_utc_year",
              "example": 2026
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "default": 1
            }
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {"$ref": "#/components/parameters/IfNoneMatchHeader"}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "Paginated event list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyEventsResponse"
                }
              }
            }
          },
          "304": {"description": "The generation-bound event page has not changed."},
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "422": {
            "description": "A validly typed year, page or page_size is outside its documented range",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {"$ref": "#/components/responses/InternalServerError"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/timeline": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getCompanyBySlugTimeline",
        "tags": ["Companies", "BORME"],
        "summary": "Get unified multi-source company timeline",
        "description": "Fail-closed derived route. Return chronological events from the exact hash-attested BORME company report and the generation/company-bound PLACSP projection. BDNS coverage is explicitly unavailable_generation_bound_projection_missing and no BDNS row, empty-list claim or fallback is emitted. If either available authority cannot be verified, the route returns 503 without reading or caching raw source data.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {"type": "string", "example": "banco-santander-s-a"},
            "description": "Company slug."
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "Multi-source timeline",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["slug", "count", "sources", "events", "coverage"],
                  "properties": {
                    "slug": {"type": "string"},
                    "count": {"type": "integer", "maximum": 100},
                    "sources": {"type": "array", "items": {"type": "string", "enum": ["borme","placsp"]}, "minItems": 2, "maxItems": 2, "example": ["borme","placsp"]},
                    "events": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "date": {"type": "string", "format": "date"},
                          "category": {"type": "string", "enum": ["borme","contratos"]},
                          "type": {"type": "string"},
                          "title": {"type": "string"},
                          "amount_eur": {"type": ["number", "null"]},
                          "source_slug": {"type": "string", "enum": ["borme","placsp"]},
                          "source_url": {"type": "string"},
                          "confidence": {"type": "string", "enum": ["high","medium","low"]},
                          "amount_semantics": {"type": "string"}
                        },
                        "additionalProperties": false
                      }
                    },
                    "coverage": {
                      "type": "object",
                      "required": ["borme", "placsp", "bdns"],
                      "properties": {
                        "borme": {"type": "string"},
                        "placsp": {"type": "string"},
                        "bdns": {"type": "string", "const": "unavailable_generation_bound_projection_missing"}
                      },
                      "additionalProperties": false
                    },
                    "_disclaimer": {"type": "string"}
                  }
                }
              }
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"},
          "429": {"$ref": "#/components/responses/TooManyRequests"}
        }
      }
    },
    "/api/v1/company/{slug}/officers": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getCompanyBySlugOfficers",
        "tags": ["Companies", "Persons"],
        "summary": "Get current and historical company officers",
        "description": "Return at most 500 officer mentions from the same cached, policy-filtered company projection used by the canonical company route. The JSON body is capped at 1 MiB. Persons are documentary mentions only — no DNI, contact data or personal address.",
        "x-rate-limit": "plan policy (see info.x-rate-limit)",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {"type": "string", "example": "banco-santander-s-a"}
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "Officer list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OfficerList"
                }
              }
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"description": "Bounded cached officer projection unavailable", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/OfflineProjectionError"}}}}
        }
      }
    },
    "/api/v1/company/{slug}/contracts": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getCompanyBySlugContracts",
        "x-query-contract": {"allowed":["limit"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"},
        "tags": ["Companies", "Public Procurement"],
        "summary": "Get PLACSP procurement notices linked to a legal entity",
        "description": "Requires the legal-first PLACSP v3 projection, including typed budget, estimate and award fields plus corporate supplier edges. It never falls back to the legacy untyped table and never sums mixed monetary concepts. A CIF link is documentary and does not prove payment or executed spend.",
        "x-rate-limit": "plan policy (see info.x-rate-limit)",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string", "example": "banco-santander-s-a"}},
          {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 30}}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "Contracts list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyProcurementResponse"
                }
              }
            }
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "422": {"$ref": "#/components/responses/ValidationFailed"},
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "500": {"$ref": "#/components/responses/InternalServerError"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/procurement": {
      "get": {
        "operationId": "getCompanyBySlugProcurement",
        "x-query-contract": {"allowed":[],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter"},
        "tags": ["Companies", "Public Procurement"],
        "summary": "Alias of /contracts",
        "description": "Documentary alias for /contracts endpoint. Same payload and projection requirements; `_alias_of` contains the canonical route.",
        "x-rate-limit": "plan policy (see info.x-rate-limit)",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}
        ],
        "responses": {
          "200": {
            "description": "Procurement awards (alias of contracts)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyProcurementResponse"
                }
              }
            }
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "500": {"$ref": "#/components/responses/InternalServerError"},
          "503": {"description": "Legal-first PLACSP projection unavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/grants": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getCompanyBySlugGrants",
        "x-query-contract": {"allowed":["limit"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"},
        "tags": ["Companies", "Public Procurement"],
        "summary": "Get BDNS public grants",
        "description": "Read only company_integrations_public_v1 after company_public_v2 admission. Returns up to 200 attested BDNS rows and never queries the canonical grants table. Monetary values are awarded amounts in integer cents, never payments; ambiguous raw zero is null. Empty is complete bounded-projection coverage, not proof of absence upstream.",
        "parameters": [
          {"$ref": "#/components/parameters/CompanySlugPath"},
          {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 200, "default": 100}},
          {"$ref": "#/components/parameters/IfNoneMatchHeader"}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "Content-Location": {"$ref": "#/components/headers/CompanyContentLocation"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "Cache-Control": {"$ref": "#/components/headers/PrivateRevalidationCacheControl"}
            },
            "description": "Grants list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyGrantsResponse"
                }
              }
            }
          },
          "304": {
            "description": "The admitted company, projection generation and legal envelope have not changed",
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "Content-Location": {"$ref": "#/components/headers/CompanyContentLocation"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "Cache-Control": {"$ref": "#/components/headers/PrivateRevalidationCacheControl"}
            }
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "422": {"$ref": "#/components/responses/ValidationFailed"},
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/ip": {
      "get": {
        "operationId": "getCompanyBySlugIp",
        "tags": ["Companies"],
        "summary": "Get policy-gated aggregated trademarks and patents",
        "description": "Fail-closed aggregate over OEPM/EUIPO/EPO data. Because upstream provenance cannot currently be separated in the aggregate, the route returns 503 until an exact aggregate-dataset decision authorizes every component and derivative use.",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}
        ],
        "responses": {
          "200": {
            "description": "Trademarks + patents counts with states legend",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "slug": {"type": "string"},
                    "trademarks": {
                      "type": "object",
                      "properties": {
                        "count": {"type": "integer"},
                        "active": {"type": "integer"},
                        "sources": {"type": "array", "items": {"type": "string"}, "example": ["OEPM","EUIPO"]}
                      }
                    },
                    "patents": {
                      "type": "object",
                      "properties": {
                        "count": {"type": "integer"},
                        "active": {"type": "integer"},
                        "sources": {"type": "array", "items": {"type": "string"}, "example": ["OEPM","EPO","WIPO"]}
                      }
                    },
                    "states_legend": {
                      "type": "object",
                      "additionalProperties": {"type": "string"}
                    }
                  }
                }
              }
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/sources": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getCompanyBySlugSources",
        "x-query-contract": {"allowed":[],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter"},
        "tags": ["Companies"],
        "summary": "Get bounded public integration coverage for a company",
        "description": "Return the four generation-bound company integration sources (BDNS, CNMV, TED and Wikidata) with explicit available/empty coverage and projection-bound license metadata. It never probes BORME, PLACSP, OEPM, GLEIF, sanctions, raw helpers or connector telemetry. Empty never proves upstream absence.",
        "parameters": [
          {"$ref": "#/components/parameters/CompanySlugPath"},
          {"$ref": "#/components/parameters/IfNoneMatchHeader"}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "Content-Location": {"$ref": "#/components/headers/CompanyContentLocation"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "Cache-Control": {"$ref": "#/components/headers/PrivateRevalidationCacheControl"}
            },
            "description": "Generation-bound coverage for exactly four safe company integrations",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/CompanySourcesResponse"}
              }
            }
          },
          "304": {
            "description": "The admitted company, projection generation and legal envelope have not changed",
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "Content-Location": {"$ref": "#/components/headers/CompanyContentLocation"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "Cache-Control": {"$ref": "#/components/headers/PrivateRevalidationCacheControl"}
            }
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/sanctions": {
      "get": {
        "operationId": "getCompanyBySlugSanctions",
        "tags": ["Companies", "Risk Signals"],
        "summary": "Get policy-gated sanctions dataset",
        "description": "This route is fail-closed. It returns data only when the exact sanctions dataset has a valid public decision, license metadata and identity policy in the active source catalog. OpenSanctions is currently in review, so the route returns 503 without reading or serializing its payload.",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}
        ],
        "responses": {
          "200": {
            "description": "Sanctions list when the exact dataset is authorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanySanctionsResponse"
                }
              }
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/daily/{date}": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getDailyByDate",
        "tags": ["BORME"],
        "summary": "Get BORME daily summary",
        "description": "Return the BORME publication summary for a given date with all acts grouped by province and type. Source: official BORME publication. Cached 24h.",
        "parameters": [
          {"name": "date", "in": "path", "required": true, "schema": {"type": "string", "format": "date", "example": "2026-05-18"}}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "Daily summary with acts list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DailySummary"
                }
              }
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/summary/date/{date}": {
      "get": {
        "operationId": "getLegacyDailySummaryByDate",
        "tags": ["BORME"],
        "summary": "Get a BORME daily summary through the legacy alias",
        "description": "Deprecated alias of `GET /api/v1/daily/{date}`. It returns the same attributed BORME daily projection; new clients must use the canonical route.",
        "deprecated": true,
        "x-replaced-by": "/api/v1/daily/{date}",
        "parameters": [
          {"name": "date", "in": "path", "required": true, "schema": {"type": "string", "format": "date", "example": "2026-05-18"}}
        ],
        "responses": {
          "200": {"description": "Daily summary with acts list", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DailySummary"}}}},
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"}
        }
      }
    },
    "/api/v1/empresa/{slug}/facts": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getEmpresaBySlugFacts",
        "x-query-contract": {"allowed":["limit"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"},
        "tags": ["Companies", "BORME"],
        "summary": "Get extracted BORME facts for a company",
        "description": "Return structured facts extracted from BORME publications grouped by type (appointments, removals, capital changes, etc.). Spanish-friendly alias of /company.",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}},
          {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 200, "default": 50}},
          {"$ref": "#/components/parameters/IfNoneMatchHeader"}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "Grouped facts",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyFactsResponse"
                }
              }
            }
          },
          "304": {"description": "The attested facts report and exact limit have not changed."},
          "400": {"$ref": "#/components/responses/BadRequest"},
          "422": {"$ref": "#/components/responses/ValidationFailed"},
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "500": {"$ref": "#/components/responses/InternalServerError"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/facts": {
      "get": {
        "operationId": "getLegacyCompanyBySlugFacts",
        "x-query-contract": {"allowed":["limit"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"},
        "tags": ["Companies", "BORME"],
        "summary": "Get extracted BORME facts through the legacy English alias",
        "description": "Deprecated alias of `GET /api/v1/empresa/{slug}/facts`. It preserves the same legal-entity subject guard and BORME source policy.",
        "deprecated": true,
        "x-replaced-by": "/api/v1/empresa/{slug}/facts",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}},
          {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 200, "default": 50}},
          {"$ref": "#/components/parameters/IfNoneMatchHeader"}
        ],
        "responses": {
          "200": {"description": "Grouped facts", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CompanyFactsResponse"}}}},
          "304": {"description": "The attested facts report and exact limit have not changed."},
          "400": {"$ref": "#/components/responses/BadRequest"},
          "422": {"$ref": "#/components/responses/ValidationFailed"},
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "500": {"$ref": "#/components/responses/InternalServerError"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/persona/{slug}": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "people:read",
        "operationId": "getPersonaBySlug",
        "tags": ["Persons"],
        "summary": "Get documentary mentions of a person",
        "description": "Return an exact, attested person_public_v1 documentary-mention report bound to the same company_public_v2 source generation. Available is 200/private no-store; absent, withheld, ambiguous or quarantined is a neutral 404; authority, hash, binding or generation failure is 503/no-store. No raw persons fallback. No DNI/NIE, contact/address, photo/social data, enrichment, sanctions, scoring, person-procurement inference, identity resolution or vigency inference.",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string", "example": "calero-brazalez-juan-jose"}}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "Cache-Control": {"schema": {"type": "string"}, "description": "no-store"}
            },
            "description": "Person documentary mentions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonDocumentaryReport"
                }
              }
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/sector/{cnae}/companies": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getSectorByCnaeCompanies",
        "x-query-contract": {"allowed":["limit","offset","sort","province"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed","combinations":"province permits only sort=recent|oldest; other documented sort values return 422"},
        "tags": ["Sectors", "Companies"],
        "summary": "Get companies by CNAE sector code",
        "description": "Return companies belonging to a given CNAE (Clasificación Nacional de Actividades Económicas) sector. CNAE codes 1-4 digits (eg. 62 = programación, 6201 = programación informática).",
        "parameters": [
          {"name": "cnae", "in": "path", "required": true, "schema": {"type": "string", "pattern": "^[0-9A-Z]{1,4}$", "example": "62"}},
          {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 20}},
          {"name": "offset", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 0, "maximum": 1000, "default": 0}},
          {"name": "sort", "in": "query", "required": false, "description": "With province only recent and oldest are accepted so the request stays index-backed.", "schema": {"type": "string", "enum": ["acts", "recent", "oldest", "name"], "default": "acts"}},
          {"name": "province", "in": "query", "required": false, "schema": {"type": "string", "maxLength": 80}}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "Companies in sector",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SectorCompaniesResponse"
                }
              }
            }
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "422": {"$ref": "#/components/responses/ValidationFailed"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"description": "Required sector-company index unavailable", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}
        }
      }
    },
    "/api/v1/company/{slug}/relationships": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getCompanyBySlugRelationships",
        "x-query-contract": {"allowed":["type","confidence"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter"},
        "tags": ["Companies"],
        "summary": "Get documentary relationships of a company",
        "description": "Return all documented relationships between this company and other entities (companies, persons, contracts, grants, IP assets, organisms). Each relationship includes source attribution, date, confidence level and evidence URL. LEGAL NOTE: relationships are documentary only — they do not imply control, responsibility, irregularity or current vigency.",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}},
          {"name": "type", "in": "query", "required": false, "schema": {"type": "string", "enum": ["officer","domicile","contract","grant","ip","corporate","mention"]}, "description": "Filter by relationship type"},
          {"name": "confidence", "in": "query", "required": false, "schema": {"type": "string", "enum": ["high","medium","low"]}}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "Documented relationships list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyRelationshipsResponse"
                }
              }
            }
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "500": {"$ref": "#/components/responses/InternalServerError"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/risk-signals": {
      "get": {
        "operationId": "getCompanyBySlugRiskSignals",
        "tags": ["Companies", "Risk Signals"],
        "summary": "Get documentary risk signals",
        "description": "Return only documentary signals whose exact dataset and negative-claim surface are authorized by the active source catalog. Other integrated sources are omitted without implying absence of the underlying fact. CENDOJ judgment text, OpenSanctions, AEPD and any unknown dataset are not exposed unless a future version records a field-specific public decision. Appearance never implies guilt, infringement, responsibility or current liability.",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}
        ],
        "responses": {
          "200": {
            "description": "Risk signals with disclaimers",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "slug": {"type": "string"},
                    "signals_count": {"type": "integer"},
                    "signals": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "type": {"type": "string", "enum": ["aepd_sanction","cnmc_sanction","concurso","aeat_moroso","cendoj_judgment","opensanctions","other"]},
                          "source_slug": {"type": "string"},
                          "source_url": {"type": "string"},
                          "date": {"type": "string", "format": "date"},
                          "summary": {"type": "string"},
                          "confidence": {"type": "string", "enum": ["high","medium","low"]},
                          "homonymy_warning": {"type": "boolean"},
                          "disclaimer": {"type": "string"}
                        }
                      }
                    },
                    "source_catalog_version": {"type": "string"},
                    "policy_scope": {"type": "string"},
                    "_legal_notice": {"type": "string", "example": "Documentary signals only. Appearance does not imply guilt, infringement or current liability."}
                  }
                }
              }
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/sector/{cnae}/ratios": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getSectorByCnaeRatios",
        "tags": ["Sectors"],
        "summary": "Get sector aggregated ratios",
        "description": "Return Banco de Espana Central de Balances aggregate metrics by two-digit CNAE division and year from the immutable, hash-addressed sector_ratios_public_v1 bundle. Coverage is sector-aggregate only: it contains neither individual-company data nor a company score. The endpoint fails closed with 503, without a raw/request-path fallback, when activation, manifest, file hash or public-source catalog authority cannot be verified.",
        "parameters": [
          {"name": "cnae", "in": "path", "required": true, "description": "Exact two-digit CNAE division present in the reviewed BdE aggregate.", "schema": {"type": "string", "pattern": "^[0-9]{2}$", "minLength": 2, "maxLength": 2}},
          {"$ref": "#/components/parameters/IfNoneMatchHeader"}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=3600, must-revalidate"}}
            },
            "description": "Sector ratios",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SectorRatiosResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not modified; the verified projection generation and legal source authority are unchanged.",
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=3600, must-revalidate"}}
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/grafo/{slug}": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getGrafoBySlug",
        "x-query-contract": {"allowed":["max_children"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"},
        "tags": ["Graph"],
        "summary": "Get corporate graph for a company",
        "description": "Return a graph centered on a company admitted by company_public_v2. Each GLEIF parent/child candidate is independently batch-admitted and its public identity is overlaid from the same sidecar; absent, personal or ambiguous candidates are omitted. SEC external nodes remain withheld until they have an external corporate-identity projection. Source-specific license metadata prevails.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "endesa-energia-sa"
            },
            "description": "Company slug."
          },
          {
            "name": "max_children",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            },
            "description": "Maximum number of children entities returned."
          },
          {"$ref": "#/components/parameters/IfNoneMatchHeader"}
        ],
        "responses": {
          "200": {
            "description": "Company corporate graph",
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "Cache-Control": {
                "schema": {"type": "string"},
                "description": "no-store"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyGraphResponse"
                }
              }
            }
          },
          "304": {"description": "The admitted graph projection has not changed."},
          "400": {"$ref": "#/components/responses/BadRequest"},
          "422": {"$ref": "#/components/responses/ValidationFailed"},
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/grafo/persona/{slug}": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "people:read",
        "operationId": "getGrafoPersonaBySlug",
        "x-query-contract": {"allowed":["limit"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"},
        "tags": ["Graph"],
        "summary": "Get person-to-company graph",
        "description": "Return a private/no-store BORME-only graph derived from an exact person_public_v1 report. Every company edge is revalidated against the same company_public_v2 generation. It contains no UK/external-person enrichment and does not infer identity, control or vigency. Withheld/absent is neutral 404; unavailable authority is 503/no-store.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "florentino-perez-rodriguez"
            },
            "description": "Person slug."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 10
            },
            "description": "Maximum number of companies returned."
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "Cache-Control": {"schema": {"type": "string", "const": "private, no-store"}}
            },
            "description": "Person graph",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonGraphResponse"
                }
              }
            }
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "422": {"$ref": "#/components/responses/ValidationFailed"},
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/health": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getHealth",
        "parameters": [{"$ref": "#/components/parameters/IfNoneMatchHeader"}],
        "tags": ["System"],
        "summary": "Service health",
        "description": "Return service status and BORME freshness from exactly one bounded global_counters_v1 offline projection. Its ETag is also bound to the shared asv1 generation used by CCAA, sector and sources, with 60-second must-revalidate caching. A cold request never opens SQLite, validates person/company sidecars, scans artifact directories, probes CSV files or rebuilds counters. Missing, legacy, malformed or future-dated projection bytes return 503.",
        "x-rate-limit": "plan policy (see info.x-rate-limit)",
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "X-OpenMercantil-Stats-Generation": {"$ref": "#/components/headers/StatsGeneration"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=60, must-revalidate"}}
            },
            "description": "Health response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          },
          "304": {
            "description": "The exact offline health representation and shared stats generation have not changed",
            "headers": {
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "X-OpenMercantil-Stats-Generation": {"$ref": "#/components/headers/StatsGeneration"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=60, must-revalidate"}}
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/stats": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getStats",
        "parameters": [{"$ref": "#/components/parameters/IfNoneMatchHeader"}],
        "tags": ["System"],
        "summary": "Published public-dataset counters",
        "description": "Return the number of legal entities actually published in the active company_public_v2 sidecar, plus an optional offline person-mention approximation. It never exposes the raw 2.8M-row companies population and never runs a request-path COUNT. Sidecar unavailability is 503, not a zero/null company count.",
        "x-rate-limit": "plan policy (see info.x-rate-limit)",
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "Stats response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total_companies": {"type": "integer", "minimum": 1, "description": "company_public_projection_state.row_count for the active bundle"},
                    "total_persons_approx": {"type": ["integer", "null"], "example": 970000},
                    "person_count_source": {"type": ["string", "null"], "enum": ["person_public_v1", null], "description": "Null means person authority unavailable; never reinterpret as zero."},
                    "person_public_source_generation": {"type": ["string", "null"], "pattern": "^cpv2-[a-f0-9]{64}$"},
                    "built_at": {"type": "string", "format": "date-time"},
                    "timestamp": {"type": "string", "format": "date-time"},
                    "version": {"type": "string", "const": "1.2"},
                    "count_source": {"type": "string", "const": "company_public_v2"}
                  },
                  "required": ["total_companies", "total_persons_approx", "person_count_source", "person_public_source_generation", "built_at", "timestamp", "version", "count_source"],
                  "additionalProperties": false
                }
              }
            }
          },
          "304": {"description": "The company-public generation and bounded statistics representation have not changed."},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/sources/freshness": {
      "get": {
        "operationId": "getSourcesFreshness",
        "parameters": [{"$ref": "#/components/parameters/IfNoneMatchHeader"}],
        "tags": ["Sources"],
        "summary": "Per-source freshness map",
        "description": "Return a minimized freshness projection only for sources authorized by the versioned public-source catalog. The timestamp comes from the offline projection, never request time. Its ETag is bound to the shared asv1 stats generation and uses 60-second must-revalidate caching. Unknown, review and restricted sources are omitted. Connector health, errors, schedules and row counts are never exposed.",
        "security": [{}, {"apiKey": []}, {"bearerAuth": []}],
        "x-api-credential-scope": "integrations:read",
        "x-rate-limit": "plan policy (see info.x-rate-limit)",
        "responses": {
          "200": {
            "description": "Freshness map",
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "X-OpenMercantil-Stats-Generation": {"$ref": "#/components/headers/StatsGeneration"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=60, must-revalidate"}}
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Fail-closed public projection. Operational ingestion telemetry is intentionally absent.",
                  "properties": {
                    "generated_at": {"type": ["string", "null"], "format": "date-time", "description": "Offline projection generation time; null only for a legacy cache without provenance."},
                    "global": {
                      "type": "object",
                      "properties": {
                        "date": {"type": ["string", "null"], "format": "date-time"},
                        "label": {"type": ["string", "null"]},
                        "status": {"type": "string", "enum": ["current","stale","unknown"]}
                      }
                    },
                    "source_catalog_version": {"type": "string"},
                    "sources": {"type": "array", "items": {"$ref": "#/components/schemas/PublicSourceMetadata"}},
                    "count": {"type": "integer"},
                    "_legal_notice": {"type": "string"}
                  }
                }
              }
            }
          },
          "304": {
            "description": "The authorized freshness representation and shared stats generation have not changed",
            "headers": {
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "X-OpenMercantil-Stats-Generation": {"$ref": "#/components/headers/StatsGeneration"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=60, must-revalidate"}}
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {
            "description": "The required offline freshness projection is absent, or the public-source legal policy cannot produce an authorized projection. This endpoint fails closed and never falls back to live connector telemetry.",
            "headers": {
              "Retry-After": {
                "description": "Seconds before retrying when the offline projection is absent.",
                "schema": {"type": "integer", "minimum": 0}
              }
            },
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/OfflineProjectionError"},
                "examples": {
                  "projection_required": {
                    "value": {"error": "offline_projection_required", "projection": "sources_freshness_v5"}
                  },
                  "legal_layer_unavailable": {
                    "value": {"error": "legal_layer_unavailable"}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/person/{slug}": {
      "get": {
        "operationId": "getLegacyPersonBySlug",
        "tags": ["Persons"],
        "summary": "Get documentary person mentions through the legacy English alias",
        "description": "Deprecated alias of `GET /api/v1/persona/{slug}`. The response remains a neutral set of attributed BORME documentary mentions, never an identity profile.",
        "deprecated": true,
        "x-replaced-by": "/api/v1/persona/{slug}",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string", "example": "calero-brazalez-juan-jose"}}
        ],
        "responses": {
          "200": {
            "description": "Same closed person_public_v1 report as the canonical Spanish route",
            "headers": {
              "Content-Location": {"schema": {"type": "string"}, "description": "Canonical /api/v1/persona/{slug} path"},
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "Cache-Control": {"schema": {"type": "string", "const": "private, no-store"}}
            },
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PersonDocumentaryReport"}}}
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/sources/status": {
      "get": {
        "operationId": "getSourcesStatus",
        "parameters": [{"$ref": "#/components/parameters/IfNoneMatchHeader"}],
        "tags": ["Sources"],
        "summary": "Minimized public source metadata",
        "description": "Return only public catalog metadata and a coarse data date/freshness. Its ETag is bound to the shared asv1 stats generation and uses 60-second must-revalidate caching. This endpoint is not an operator health probe and does not expose connector status, errors, schedules, source URLs or item counts.",
        "x-rate-limit": "free 60/min · 200/day",
        "responses": {
          "200": {
            "description": "Fail-closed public source projection",
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "X-OpenMercantil-Stats-Generation": {"$ref": "#/components/headers/StatsGeneration"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=60, must-revalidate"}}
            },
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicSourceStatusResponse"}}}
          },
          "304": {
            "description": "The minimized source-status representation and shared stats generation have not changed",
            "headers": {
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "X-OpenMercantil-Stats-Generation": {"$ref": "#/components/headers/StatsGeneration"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=60, must-revalidate"}}
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/ccaa/stats.json": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getCcaaStatsJson",
        "parameters": [{"$ref": "#/components/parameters/IfNoneMatchHeader"}],
        "tags": ["Datasets"],
        "summary": "Aggregates by autonomous community (CCAA)",
        "description": "Return per-CCAA totals from the offline projection. The ETag is bound to the shared asv1 stats generation and uses 60-second must-revalidate caching. Award-procedure counts come only from the corporate PLACSP v3 summary; the deprecated `contracts_count` is an explicitly labelled alias and `contracts_total_eur` is always withheld. Also available without `.json` suffix. Returns 503 rather than rebuilding aggregates in PHP-FPM.",
        "x-rate-limit": "plan policy (see info.x-rate-limit)",
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "X-OpenMercantil-Stats-Generation": {"$ref": "#/components/headers/StatsGeneration"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=60, must-revalidate"}}
            },
            "description": "CCAA stats",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CcaaStatsResponse"
                }
              }
            }
          },
          "304": {
            "description": "The CCAA representation and shared stats generation have not changed",
            "headers": {
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "X-OpenMercantil-Stats-Generation": {"$ref": "#/components/headers/StatsGeneration"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=60, must-revalidate"}}
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/ccaa/stats": {
      "get": {
        "operationId": "getLegacyCcaaStats",
        "parameters": [{"$ref": "#/components/parameters/IfNoneMatchHeader"}],
        "tags": ["Datasets"],
        "summary": "Get CCAA aggregates through the suffix-less legacy alias",
        "description": "Deprecated alias of `GET /api/v1/ccaa/stats.json`. It reads the same bounded offline projection and never rebuilds aggregates in the request path.",
        "deprecated": true,
        "x-replaced-by": "/api/v1/ccaa/stats.json",
        "x-rate-limit": "plan policy (see info.x-rate-limit)",
        "responses": {
          "200": {
            "description": "CCAA stats",
            "headers": {
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "X-OpenMercantil-Stats-Generation": {"$ref": "#/components/headers/StatsGeneration"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=60, must-revalidate"}}
            },
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CcaaStatsResponse"}}}
          },
          "304": {
            "description": "The canonical CCAA representation and shared stats generation have not changed",
            "headers": {
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "X-OpenMercantil-Stats-Generation": {"$ref": "#/components/headers/StatsGeneration"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=60, must-revalidate"}}
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"description": "Offline projection missing or stale"}
        }
      }
    },
    "/api/v1/sectores/stats.json": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getSectoresStatsJson",
        "parameters": [{"$ref": "#/components/parameters/IfNoneMatchHeader"}],
        "tags": ["Datasets"],
        "summary": "Aggregates by CNAE sector",
        "description": "Return per-CNAE section totals from the offline projection. The ETag is bound to the shared asv1 stats generation and uses 60-second must-revalidate caching. Procurement fields distinguish award procedures from contracts and never expose an untyped monetary rollup. Also available as CSV. Returns 503 instead of executing a live GROUP BY.",
        "x-rate-limit": "plan policy (see info.x-rate-limit)",
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "X-OpenMercantil-Stats-Generation": {"$ref": "#/components/headers/StatsGeneration"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=60, must-revalidate"}}
            },
            "description": "Sector stats",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SectorStatsResponse"}}}
          },
          "304": {
            "description": "The sector representation and shared stats generation have not changed",
            "headers": {
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "X-OpenMercantil-Stats-Generation": {"$ref": "#/components/headers/StatsGeneration"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=60, must-revalidate"}}
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/sectores/stats": {
      "get": {
        "operationId": "getLegacySectoresStats",
        "parameters": [{"$ref": "#/components/parameters/IfNoneMatchHeader"}],
        "tags": ["Datasets"],
        "summary": "Get CNAE-sector aggregates through the suffix-less legacy alias",
        "description": "Deprecated alias of `GET /api/v1/sectores/stats.json`. It reads the same bounded offline projection and never executes a live GROUP BY.",
        "deprecated": true,
        "x-replaced-by": "/api/v1/sectores/stats.json",
        "x-rate-limit": "plan policy (see info.x-rate-limit)",
        "responses": {
          "200": {
            "description": "Sector stats",
            "headers": {
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "X-OpenMercantil-Stats-Generation": {"$ref": "#/components/headers/StatsGeneration"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=60, must-revalidate"}}
            },
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SectorStatsResponse"}}}
          },
          "304": {
            "description": "The canonical sector representation and shared stats generation have not changed",
            "headers": {
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "X-OpenMercantil-Stats-Generation": {"$ref": "#/components/headers/StatsGeneration"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=60, must-revalidate"}}
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"description": "Offline projection missing or stale"}
        }
      }
    },
    "/api/v1/sectores/stats.csv": {
      "get": {
        "operationId": "getSectoresStatsCsv",
        "parameters": [{"$ref": "#/components/parameters/IfNoneMatchHeader"}],
        "tags": ["Datasets"],
        "summary": "Aggregates by CNAE sector (CSV)",
        "description": "Offline sector projection rendered as a bounded CSV representation with a shared-asv1 generation ETag and 60-second must-revalidate caching; no aggregation occurs in the request path. Canonical `award_procedures_count` and all semantic-status columns are included; `contracts_total_eur` remains empty/withheld.",
        "x-rate-limit": "plan policy (see info.x-rate-limit)",
        "responses": {
          "200": {
            "description": "Sector stats CSV",
            "headers": {
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "X-OpenMercantil-Stats-Generation": {"$ref": "#/components/headers/StatsGeneration"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=60, must-revalidate"}}
            },
            "content": {"text/csv": {"schema": {"type": "string"}}}
          },
          "304": {
            "description": "The bounded sector CSV representation and shared stats generation have not changed",
            "headers": {
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "X-OpenMercantil-Stats-Generation": {"$ref": "#/components/headers/StatsGeneration"},
              "Cache-Control": {"schema": {"type": "string", "const": "public, max-age=60, must-revalidate"}}
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"description": "Offline projection missing or stale"}
        }
      }
    },
    "/api/v1/cnae/tree": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getCnaeTree",
        "tags": ["Sectors"],
        "summary": "Hierarchical CNAE tree",
        "description": "Return the CNAE-2009 hierarchy with counts read only from the offline sector projection. Cached 24h; no live aggregation is performed.",
        "x-rate-limit": "plan policy (see info.x-rate-limit)",
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "CNAE tree",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CnaeTreeResponse"
                }
              }
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/cnae/{code}": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getCnaeByCode",
        "tags": ["Sectors"],
        "summary": "CNAE code metadata",
        "description": "Return CNAE-2009 metadata and an optional company count from the offline projection. A missing projection is represented as null and never triggers a live COUNT.",
        "x-rate-limit": "plan policy (see info.x-rate-limit)",
        "parameters": [
          {"name": "code", "in": "path", "required": true, "schema": {"type": "string", "pattern": "^[0-9A-Z]{1,4}$", "example": "6201"}}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "CNAE metadata",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CnaeNode"
                }
              }
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/person/search": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "people:read",
        "operationId": "getPersonSearch",
        "x-query-contract": {"allowed":["q","limit"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"},
        "tags": ["Persons", "Search"],
        "summary": "Search documentary mentions of persons",
        "description": "Search only person_public_search_v1, bounded to 50 results and revalidated against the activated company_public_v2 generation. Results are unresolved name mentions, never identity profiles. Authority failure is 503/no-store, not an empty result. No raw persons, enrichment or person-procurement fallback.",
        "x-rate-limit": "free 60/min · 200/day",
        "parameters": [
          {"name": "q", "in": "query", "required": true, "schema": {"type": "string", "minLength": 2, "maxLength": 200, "example": "garcia"}},
          {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 50, "default": 20}}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "Cache-Control": {"schema": {"type": "string", "const": "private, no-store"}}
            },
            "description": "Person search results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonSearchResponse"
                }
              }
            }
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "422": {"$ref": "#/components/responses/ValidationFailed"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/persona/{slug}/contracts": {
      "get": {
        "operationId": "getPersonaBySlugContracts",
        "tags": ["Persons", "Public Procurement"],
        "summary": "Person-to-procurement derivation (unavailable)",
        "description": "Fail-closed derived route. It always returns 503 before reading data because `person_contracts_v1` is not authorized. A future implementation requires a new reviewed projection and contract version.",
        "deprecated": true,
        "x-rate-limit": "plan policy (see info.x-rate-limit)",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}
        ],
        "responses": {
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/lei": {
      "get": {
        "operationId": "getCompanyBySlugLei",
        "tags": ["Companies"],
        "summary": "Get policy-gated GLEIF LEI record",
        "description": "Fail-closed route. GLEIF license declarations conflict in repository evidence and the dataset remains in review; the route returns 503 until a future catalog version records an exact validated public decision.",
        "x-rate-limit": "free 60/min · 200/day",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "LEI record when GLEIF is authorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyLeiResponse"
                }
              }
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/bde": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getCompanyBySlugBde",
        "tags": ["Companies"],
        "summary": "Get Banco de España sector ratios for a company CNAE",
        "description": "Join the already admitted company_public_v2 identity to the immutable Central de Balances sector projection using the company's two-digit CNAE. The response binds both immutable generations. This is sector benchmarking, not a supervised-entity record, company-specific financial statement or score. coverage_status distinguishes a missing CNAE, an unprojected sector and a match; empty coverage never proves that no Banco de España data exists.",
        "x-rate-limit": "free 60/min · 200/day",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "CNAE sector-ratio projection or its documented empty shape",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyBdeResponse"
                }
              }
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/cnmv": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getCompanyBySlugCnmv",
        "x-query-contract": {"allowed":["limit"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"},
        "tags": ["Companies"],
        "summary": "Get the CNMV listed-company projection and recent events",
        "description": "Read only company_integrations_public_v1 after company_public_v2 admission. Returns one minimized listing tuple and up to 20 attested documentary events. It does not certify current supervision or imply a negative fact; empty coverage is not proof of non-listing.",
        "x-rate-limit": "free 60/min · 200/day",
        "parameters": [
          {"$ref": "#/components/parameters/CompanySlugPath"},
          {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 20, "default": 5}},
          {"$ref": "#/components/parameters/IfNoneMatchHeader"}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "Content-Location": {"$ref": "#/components/headers/CompanyContentLocation"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "Cache-Control": {"$ref": "#/components/headers/PrivateRevalidationCacheControl"}
            },
            "description": "CNMV listed-company projection or its documented empty shape",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyCnmvResponse"
                }
              }
            }
          },
          "304": {
            "description": "The admitted company, projection generation and legal envelope have not changed",
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "Content-Location": {"$ref": "#/components/headers/CompanyContentLocation"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "Cache-Control": {"$ref": "#/components/headers/PrivateRevalidationCacheControl"}
            }
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "422": {"$ref": "#/components/responses/ValidationFailed"},
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/aeat-moroso": {
      "get": {
        "operationId": "getCompanyBySlugAeatMoroso",
        "tags": ["Companies", "Risk Signals"],
        "summary": "Check policy-gated AEAT debtor-list mention",
        "description": "Negative-claim route gated before lookup. It returns 503 until the exact AEAT dataset has validated reuse, identity-match and cite-or-abstain policy metadata. Appearance would be documentary only and never imply current liability.",
        "x-rate-limit": "free 60/min · 200/day",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}
        ],
        "responses": {
          "200": {
            "description": "Debtor list mention or empty",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyAeatDebtorResponse"
                }
              }
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/wikidata": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getCompanyBySlugWikidata",
        "x-query-contract": {"allowed":[],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter"},
        "tags": ["Companies"],
        "summary": "Get the bounded Wikidata company metadata projection",
        "description": "Read only the CC0 structured subset in company_integrations_public_v1 after company_public_v2 admission: Q-id, entity URL, ticker and inception. Labels, logos, websites, CEO text, LEI and Wikipedia content are excluded. Empty coverage is not proof that the company is absent upstream.",
        "x-rate-limit": "free 60/min · 200/day",
        "parameters": [
          {"$ref": "#/components/parameters/CompanySlugPath"},
          {"$ref": "#/components/parameters/IfNoneMatchHeader"}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "Content-Location": {"$ref": "#/components/headers/CompanyContentLocation"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "Cache-Control": {"$ref": "#/components/headers/PrivateRevalidationCacheControl"}
            },
            "description": "Wikidata metadata projection or its documented empty shape",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyWikidataResponse"
                }
              }
            }
          },
          "304": {
            "description": "The admitted company, projection generation and legal envelope have not changed",
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "Content-Location": {"$ref": "#/components/headers/CompanyContentLocation"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "Cache-Control": {"$ref": "#/components/headers/PrivateRevalidationCacheControl"}
            }
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/ted": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getCompanyBySlugTed",
        "x-query-contract": {"allowed":["limit"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"},
        "tags": ["Companies", "Public Procurement"],
        "summary": "Get TED notice records linked to this corporate NIF",
        "description": "Read only company_integrations_public_v1 after company_public_v2 admission. Returns up to 100 minimized TED notice links: publication number/date, buyer and official notice URL. Tenderer, currency and free-form connector fields are excluded. Rows do not prove payment, executed spend or current contractual status.",
        "x-rate-limit": "free 60/min · 200/day",
        "parameters": [
          {"$ref": "#/components/parameters/CompanySlugPath"},
          {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50}},
          {"$ref": "#/components/parameters/IfNoneMatchHeader"}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "Content-Location": {"$ref": "#/components/headers/CompanyContentLocation"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "Cache-Control": {"$ref": "#/components/headers/PrivateRevalidationCacheControl"}
            },
            "description": "Bounded TED documentary records linked to the admitted corporate NIF",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyTedResponse"
                }
              }
            }
          },
          "304": {
            "description": "The admitted company, projection generation and legal envelope have not changed",
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "Content-Location": {"$ref": "#/components/headers/CompanyContentLocation"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "Cache-Control": {"$ref": "#/components/headers/PrivateRevalidationCacheControl"}
            }
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "422": {"$ref": "#/components/responses/ValidationFailed"},
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/accounts": {
      "get": {
        "operationId": "getCompanyBySlugAccounts",
        "tags": ["Companies"],
        "summary": "Get policy-gated filed accounts metadata",
        "description": "Fail-closed aggregate over mixed CNMV, BORME section II and REA-derived metadata. The route returns 503 until provenance can be filtered before aggregate fields are calculated and the exact annual-accounts decision becomes public.",
        "x-rate-limit": "free 60/min · 200/day",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "Accounts metadata list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyAccountsResponse"
                }
              }
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/geocode": {
      "get": {
        "operationId": "getCompanyBySlugGeocode",
        "tags": ["Companies"],
        "summary": "Company geocode projection (unavailable)",
        "description": "Fail-closed route. Address parsing and Nominatim access are forbidden in the request path; it always returns 503 until an approved offline `company_geocode_v1` projection exists. Enabling the source policy alone cannot activate network or database writes.",
        "deprecated": true,
        "x-rate-limit": "free 60/min · 200/day",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}
        ],
        "responses": {
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/activity": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "companies:read",
        "operationId": "getCompanyBySlugActivity",
        "tags": ["Companies"],
        "summary": "Activity time series",
        "description": "Return monthly registry activity count for the company over the last N months. Useful for sparklines.",
        "x-rate-limit": "free 60/min · 200/day",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}},
          {"$ref": "#/components/parameters/IfNoneMatchHeader"}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "Time series",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyActivityResponse"
                }
              }
            }
          },
          "304": {"description": "The admitted activity projection has not changed."},
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"description": "Source policy, subject classification or activity projection unavailable", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}
        }
      }
    },
    "/api/v1/company/{slug}/score": {
      "get": {
        "operationId": "getCompanyBySlugScore",
        "tags": ["Companies"],
        "summary": "Documentary completeness score (no risk/credit scoring)",
        "description": "Fail-closed derived route. Return a documentary completeness indicator only after the exact score derivation is explicitly authorized in the active public source catalog. It is never a credit, risk or trust score. Until authorization, the route returns 503 before reading data.",
        "x-rate-limit": "free 60/min · 200/day",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}
        ],
        "responses": {
          "200": {
            "description": "Completeness score",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyActivityScoreResponse"
                }
              }
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/similar": {
      "get": {
        "operationId": "getCompanyBySlugSimilar",
        "x-query-contract": {"allowed":["limit"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"},
        "tags": ["Companies"],
        "summary": "Similar companies (province + CNAE2 + BORME activity)",
        "description": "Return admitted companies in the same province and published two-digit CNAE division, ranked by proximity of BORME act count. This documentary heuristic is neither a relationship nor a recommendation; every result is independently admitted by company_public_v2.",
        "security": [{}, {"apiKey": []}, {"bearerAuth": []}],
        "x-api-credential-scope": "companies:read",
        "x-rate-limit": "free 60/min · 200/day",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}},
          {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 20, "default": 8}}
        ],
        "responses": {
          "200": {
            "description": "Similar companies list",
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanySimilarResponse"
                }
              }
            }
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "422": {"$ref": "#/components/responses/ValidationFailed"},
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/embargoes": {
      "get": {
        "operationId": "getCompanyBySlugEmbargoes",
        "tags": ["Companies", "Risk Signals"],
        "summary": "Documentary embargo/garnishment mentions",
        "description": "Return documentary mentions of embargoes (embargo de bienes, anotaciones registrales) when published in public registries. Documentary only — does not certify current status.",
        "x-rate-limit": "free 60/min · 200/day",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}
        ],
        "responses": {
          "200": {
            "description": "Embargo mentions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyEmbargoesResponse"
                }
              }
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/company/{slug}/network": {
      "get": {
        "operationId": "getCompanyBySlugNetwork",
        "tags": ["Companies", "Graph"],
        "summary": "Documentary network projection (temporarily unavailable)",
        "description": "The former synchronous graph calculation is disabled because its cold path exceeded the request budget. This route returns 503 until an indexed, legally governed offline projection is available.",
        "deprecated": true,
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}
        ],
        "responses": {
          "404": {"$ref": "#/components/responses/NotFound"},
          "503": {
            "description": "Offline projection required",
            "content": {"application/json": {"schema": {
              "$ref": "#/components/schemas/OfflineProjectionError"
            }}}
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"}
        }
      }
    },
    "/api/v1/company/{slug}/enrichment": {
      "get": {
        "operationId": "getCompanyBySlugEnrichment",
        "tags": ["Companies"],
        "summary": "Fail-closed public enrichment payload",
        "description": "Return only datasets authorized by the versioned public-source catalog. Unknown, review and restricted datasets are removed with their data before caching. The response includes license, attribution and policy-date metadata for every source that remains.",
        "x-rate-limit": "free 60/min · 200/day",
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}},
          {"$ref": "#/components/parameters/IfNoneMatchHeader"}
        ],
        "responses": {
          "200": {
            "description": "Enrichment payload",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyEnrichmentResponse"
                }
              }
            }
          },
          "304": {"description": "The admitted enrichment projection and source policy have not changed."},
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/contracts/top-companies": {
      "get": {
        "operationId": "getContractsTopCompanies",
        "x-query-contract": {"allowed":["limit"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"},
        "tags": ["Public Procurement", "Datasets"],
        "summary": "Corporate suppliers ranked by PLACSP award procedures",
        "description": "Compatibility alias of `/api/v1/tenders/suppliers`. Reads only `placsp_public_company_summary`, ranks corporate suppliers by award-procedure count and never publishes a monetary ranking or rollup. Natural persons are excluded. `province` and `cnae` are rejected until dedicated offline projections exist.",
        "parameters": [
          {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 50, "default": 20}}
        ],
        "x-rate-limit": "plan policy (see info.x-rate-limit); enforced before projection access",
        "responses": {
          "200": {
            "description": "Sanitized corporate supplier ranking",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TenderSupplierResponse"}}}
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "422": {"$ref": "#/components/responses/ValidationFailed"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "500": {"$ref": "#/components/responses/InternalServerError"},
          "503": {"description": "PLACSP public projection unavailable"}
        }
      }
    },
    "/api/v1/contracts/top-persons": {
      "get": {
        "operationId": "getContractsTopPersons",
        "tags": ["Public Procurement", "Datasets"],
        "summary": "Top persons by PLACSP-signatory companies",
        "description": "Fail-closed derived route. It always returns 503 before reading data because `person_contracts_v1` is not authorized. A future implementation requires a new reviewed projection and contract version.",
        "deprecated": true,
        "x-rate-limit": "plan policy (see info.x-rate-limit)",
        "responses": {
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/contracts/top-companies.csv": {
      "get": {
        "operationId": "getContractsTopCompaniesCsv",
        "x-query-contract": {"allowed":["limit"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"},
        "tags": ["Public Procurement", "Datasets"],
        "summary": "Corporate suppliers by award procedures (CSV)",
        "description": "Bounded CSV (maximum 100 rows) generated from `placsp_public_company_summary`. Columns distinguish notice count from award-procedure count and contain no monetary aggregate.",
        "parameters": [
          {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 100}}
        ],
        "x-rate-limit": "plan policy (see info.x-rate-limit); enforced before projection access",
        "responses": {
          "200": {
            "description": "CSV download",
            "content": {"text/csv": {"schema": {"type": "string"}}}
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "422": {"$ref": "#/components/responses/ValidationFailed"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "500": {"$ref": "#/components/responses/InternalServerError"},
          "503": {"description": "PLACSP public projection unavailable"}
        }
      }
    },
    "/api/v1/contracts/top-persons.csv": {
      "get": {
        "operationId": "getContractsTopPersonsCsv",
        "x-query-contract": {"allowed":[],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter"},
        "tags": ["Public Procurement", "Datasets"],
        "summary": "Top persons by PLACSP-signatory companies (CSV)",
        "description": "Fail-closed CSV equivalent of `/api/v1/contracts/top-persons`; it always returns 503 before reading data.",
        "deprecated": true,
        "x-rate-limit": "plan policy (see info.x-rate-limit)",
        "responses": {
          "400": {"$ref": "#/components/responses/BadRequest"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/export/events": {
      "get": {
        "operationId": "getExportEvents",
        "tags": ["Datasets"],
        "summary": "Bulk BORME export (offline artifact required)",
        "description": "Fail-closed endpoint with no query contract. It always returns 503 until a governed pre-sanitized static artifact contract exists; the API never scans or redacts the full BORME CSV in PHP-FPM.",
        "deprecated": true,
        "responses": {
          "503": {
            "description": "Pre-sanitized offline artifact is not available",
            "content": {"application/json": {"schema": {
              "$ref": "#/components/schemas/OfflineProjectionError"
            }}}
          }
        }
      }
    },
    "/api/v1/export/companies": {
      "get": {
        "operationId": "getExportCompanies",
        "tags": ["Datasets"],
        "summary": "Request an offline company export artifact (currently unavailable)",
        "description": "The route preserves API credential, exports:read scope, paid-tier and action-budget checks, then always returns 503 offline_export_required. PHP-FPM never filters, sorts, paginates or serializes a bulk company export. The historical query parameters remain documented only so clients can remove them.",
        "deprecated": true,
        "x-status": "offline-artifact-required",
        "x-rate-limit": "2/minute and 20/day per authenticated user",
        "security": [{"apiKey": []}],
        "parameters": [
        {
          "name": "provincia",
          "in": "query",
          "required": false,
          "deprecated": true,
            "description": "Exact province value used by the company projection, or `all`.",
            "schema": {
              "type": "string",
              "maxLength": 80
            }
          },
        {
          "name": "tipo",
          "in": "query",
          "required": false,
          "deprecated": true,
            "description": "Company-form suffix filter such as SL, SA or SLU.",
            "schema": {
              "type": "string",
              "maxLength": 20
            }
          },
        {
          "name": "año",
          "in": "query",
          "required": false,
          "deprecated": true,
            "description": "Four-digit first-seen year. The runtime parameter name contains `ñ`.",
            "schema": {
              "type": "string",
              "pattern": "^20\\d{2}$"
            }
          },
        {
          "name": "limit",
          "in": "query",
          "required": false,
          "deprecated": true,
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5000,
              "default": 1000
            }
          },
        {
          "name": "offset",
          "in": "query",
          "required": false,
          "deprecated": true,
          "schema": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100000,
              "default": 0
            }
          },
        {
          "name": "formato",
          "in": "query",
          "required": false,
          "deprecated": true,
            "schema": {
              "type": "string",
              "enum": [
                "csv",
                "json"
              ],
              "default": "csv"
            }
          }
        ],
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Scope or paid plan required"
          },
          "429": {
            "description": "Export-specific rate limit exceeded"
          },
          "503": {
            "description": "A pre-sanitized offline export artifact is required",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/OfflineProjectionError"}}}
          }
        }
      }
    },
    "/api/v1/company/{slug}/export": {
      "get": {
        "operationId": "getCompanyBySlugExport",
        "x-query-contract": {"allowed":[],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter"},
        "tags": ["Companies", "Datasets"],
        "summary": "Export a single company report",
        "description": "Return the same policy-filtered cached company projection as the canonical company route, serialized as downloadable JSON. The response is capped at 8 MiB and fails closed instead of rebuilding an oversized payload.",
        "x-rate-limit": "plan policy (see info.x-rate-limit)",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Export",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyReport"
                }
              }
            }
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"description": "Bounded cached company projection unavailable", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/OfflineProjectionError"}}}}
        }
      }
    },
    "/api/v1/user/me": {
      "get": {
        "operationId": "getUserMe",
        "tags": ["User"],
        "summary": "Current authenticated user",
        "description": "Returns id, email, name, plan (tier), persona_primary, onboarded flag and a fresh CSRF token. Requires active session cookie.",
        "security": [{"cookieAuth": []}],
        "responses": {
          "200": {
            "description": "User profile",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserMeResponse"
                }
              }
            }
          },
          "401": {"$ref": "#/components/responses/Unauthorized"}
        }
      }
    },
    "/api/v1/user/org": {
      "get": {
        "operationId": "getUserOrganization",
        "tags": ["User"],
        "summary": "Get the current organization, seats and visible members",
        "description": "Returns null organization plus can_team when the user has no team. Non-privileged members receive masked peer email addresses; the caller's own email is never masked. Invitation tokens are never returned.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "responses": {
          "200": {
            "description": "Organization context",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserOrganizationResponse"
                }
              }
            }
          },
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "503": {"description": "Organization service unavailable"}
        }
      },
      "post": {
        "operationId": "createUserOrganization",
        "tags": ["User"],
        "summary": "Create an organization",
        "description": "MAX/Enterprise account mutation. The authenticated user becomes owner.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/CsrfHeader"}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserOrganizationNameRequest"}}}},
        "responses": {"201": {
          "description": "Organization created",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrganizationCreatedResponse"
              }
            }
          }
        }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "402": {"description": "Plan does not include teams"}, "403": {"description": "Invalid CSRF"}, "409": {"description": "User already belongs to an organization"}, "503": {"description": "Organization service unavailable"}}
      },
      "put": {
        "operationId": "updateUserOrganization",
        "tags": ["User"],
        "summary": "Rename the current organization",
        "description": "Owner-only account mutation.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/CsrfHeader"}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserOrganizationNameRequest"}}}},
        "responses": {"200": {
          "description": "Organization renamed",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OkResponse"
              }
            }
          }
        }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Owner permission or CSRF required"}, "404": {"$ref": "#/components/responses/NotFound"}, "503": {"description": "Organization service unavailable"}}
      }
    },
    "/api/v1/user/org/invites": {
      "post": {
        "operationId": "createUserOrganizationInvite",
        "tags": ["User"],
        "summary": "Create or renew an organization invitation",
        "description": "Owner/admin mutation. Enforces seat and daily invitation limits, sends the invitation out of band and never returns its token.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/CsrfHeader"}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserOrganizationInviteRequest"}}}},
        "responses": {"201": {
          "description": "Invitation created or renewed without token",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrganizationInviteCreatedResponse"
              }
            }
          }
        }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Owner/admin permission or CSRF required"}, "409": {"description": "No organization, duplicate member or no free seat"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"description": "Organization or email service unavailable"}}
      }
    },
    "/api/v1/user/org/invites/{id}/resend": {
      "post": {
        "operationId": "resendUserOrganizationInvite",
        "tags": ["User"],
        "summary": "Rotate and resend an organization invitation",
        "description": "Owner/admin mutation with no request body. The rotated token is sent out of band and never returned.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}],
        "responses": {"200": {
          "description": "Invitation resent",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailDispatchResponse"
              }
            }
          }
        }, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Owner/admin permission or CSRF required"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"description": "No free seat for an expired invitation"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"description": "Organization or email service unavailable"}}
      }
    },
    "/api/v1/user/org/invites/{id}": {
      "delete": {
        "operationId": "deleteUserOrganizationInvite",
        "tags": ["User"],
        "summary": "Cancel a pending organization invitation",
        "description": "Owner/admin mutation with no request body.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}],
        "responses": {"200": {
          "description": "Invitation cancelled",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OkResponse"
              }
            }
          }
        }, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Owner/admin permission or CSRF required"}, "404": {"$ref": "#/components/responses/NotFound"}, "503": {"description": "Organization service unavailable"}}
      }
    },
    "/api/v1/user/org/members/{id}": {
      "put": {
        "operationId": "updateUserOrganizationMember",
        "tags": ["User"],
        "summary": "Change an organization member role",
        "description": "Owner-only mutation; the owner and caller's own role cannot be changed.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserOrganizationMemberRoleRequest"}}}},
        "responses": {"200": {
          "description": "Role updated",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OkResponse"
              }
            }
          }
        }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Owner permission or CSRF required"}, "404": {"$ref": "#/components/responses/NotFound"}, "503": {"description": "Organization service unavailable"}}
      },
      "delete": {
        "operationId": "deleteUserOrganizationMember",
        "tags": ["User"],
        "summary": "Remove a member from the organization",
        "description": "Owner/admin mutation with no request body. Admins may remove members but not owners or other admins.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}],
        "responses": {"200": {
          "description": "Member removed",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OkResponse"
              }
            }
          }
        }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Owner/admin permission or CSRF required"}, "404": {"$ref": "#/components/responses/NotFound"}, "503": {"description": "Organization service unavailable"}}
      }
    },
    "/api/v1/user/org/leave": {
      "post": {
        "operationId": "leaveUserOrganization",
        "tags": ["User"],
        "summary": "Leave the current organization",
        "description": "Member/admin mutation with no request body. Owners must transfer ownership through the supported process before leaving.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/CsrfHeader"}],
        "responses": {"200": {
          "description": "Organization left",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OkResponse"
              }
            }
          }
        }, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"description": "Owner cannot leave before transferring ownership"}, "503": {"description": "Organization service unavailable"}}
      }
    },
    "/api/v1/user/persona": {
      "get": {
        "operationId": "getUserPersona",
        "tags": ["User"],
        "summary": "Current persona config + available list",
        "security": [{"cookieAuth": []}],
        "responses": {"200": {
          "description": "Persona config",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserPersonaResponse"
              }
            }
          }
        }, "401": {"$ref": "#/components/responses/Unauthorized"}}
      },
      "post": {
        "operationId": "postUserPersona",
        "tags": ["User"],
        "summary": "Set persona_primary",
        "description": "Set the account persona to a slug returned by the GET operation.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/CsrfHeader"}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserPersonaUpdateRequest"}}}},
        "responses": {"200": {
          "description": "Updated",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserPersonaSelectedResponse"
              }
            }
          }
        }, "400": {"description": "Invalid persona slug"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}}
      }
    },
    "/api/v1/user/segments": {
      "get": {
        "operationId": "getUserSegments",
        "x-query-contract": {"allowed":["pinned","limit"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"},
        "tags": ["User"],
        "summary": "List user segments",
        "parameters": [
          {"name": "pinned", "in": "query", "schema": {"type": "string", "enum": ["0", "1"]}},
          {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 500, "default": 200}}
        ],
        "security": [{"cookieAuth": []}],
        "responses": {"200": {
          "description": "Segments list with tier_max",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserSegmentListResponse"
              }
            }
          }
        }, "400": {"$ref": "#/components/responses/BadRequest"}, "422": {"$ref": "#/components/responses/ValidationFailed"}, "401": {"$ref": "#/components/responses/Unauthorized"}}
      },
      "post": {
        "operationId": "postUserSegments",
        "tags": ["User"],
        "summary": "Create segment",
        "description": "Create a tier-limited saved corporate segment. At least one effective UserSegmentFilters anchor is required. Unknown fields and legacy forma/estado filters are rejected with 400; an individually valid but unindexed combination is rejected with 422.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/CsrfHeader"}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserSegmentCreateRequest"}}}},
        "responses": {"201": {
          "description": "Created",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserSegmentCreatedResponse"
              }
            }
          }
        }, "400": {"description": "Malformed/unknown filter, legally unavailable legacy filter, missing effective anchor or tier limit", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "422": {"description": "Individually valid filters do not have a safe indexed combination", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}}
      }
    },
    "/api/v1/user/segments/{id}": {
      "get": {"operationId": "getUserSegmentsById", "tags": ["User"], "summary": "Get segment", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {
        "description": "Segment",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UserSegment"
            }
          }
        }
      }, "404": {"$ref": "#/components/responses/NotFound"}}},
      "put": {"operationId": "putUserSegmentsById", "tags": ["User"], "summary": "Replace mutable segment fields", "description": "When filters_json is present it follows UserSegmentFilters. Invalid or legacy fields return 400; unsupported indexed combinations return 422.", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserSegmentUpdateRequest"}}}}, "responses": {"200": {
        "description": "Updated",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/OkResponse"
            }
          }
        }
      }, "400": {"description": "Malformed/unknown or legally unavailable filter", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "422": {"description": "Individually valid filters do not have a safe indexed combination", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}, "404": {"$ref": "#/components/responses/NotFound"}}},
      "patch": {"operationId": "patchUserSegmentsById", "tags": ["User"], "summary": "Patch mutable segment fields", "description": "When filters_json is present it follows UserSegmentFilters. Invalid or legacy fields return 400; unsupported indexed combinations return 422.", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserSegmentUpdateRequest"}}}}, "responses": {"200": {
        "description": "Updated",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/OkResponse"
            }
          }
        }
      }, "400": {"description": "Malformed/unknown or legally unavailable filter", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "422": {"description": "Individually valid filters do not have a safe indexed combination", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}, "404": {"$ref": "#/components/responses/NotFound"}}},
      "delete": {"operationId": "deleteUserSegmentsById", "tags": ["User"], "summary": "Delete segment", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}], "responses": {"200": {
        "description": "Deleted",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/OkResponse"
            }
          }
        }
      }, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}}}
    },
    "/api/v1/user/segments/{id}/pin": {
      "post": {"operationId": "postUserSegmentsByIdPin", "tags": ["User"], "summary": "Toggle pin", "description": "This mutation has no request body.", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}], "responses": {"200": {
        "description": "New pinned state",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UserSegmentPinResponse"
            }
          }
        }
      }, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}, "404": {"$ref": "#/components/responses/NotFound"}}}
    },
    "/api/v1/user/segments/{id}/run": {
      "post": {"operationId": "postUserSegmentsByIdRun", "x-query-contract": {"allowed":["limit"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"}, "tags": ["User"], "summary": "Execute segment filters → companies", "description": "Resolves filters_json only against the immutable corporate company_public_v2 sidecar and returns at most 500 rows. `count` is the number of rows in this bounded response, not an exact global total. Invalid/legacy filters return 400, unsupported indexed combinations return 422, and missing authority/sidecar or query failure returns 503. This mutation has no request body.", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "default": 100, "maximum": 500}}, {"$ref": "#/components/parameters/CsrfHeader"}], "responses": {"200": {
        "description": "Bounded result rows; count equals rows.length and is not a global total",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UserSegmentRunResponse"
            }
          }
        }
      }, "400": {"description": "Malformed/unknown or legally unavailable saved filter", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "422": {"description": "Saved filters are valid individually but lack a safe indexed combination", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}, "404": {"$ref": "#/components/responses/NotFound"}, "503": {"description": "Canonical authority, legal layer, immutable company sidecar or bounded query unavailable", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}
    },
    "/api/v1/user/lists": {
      "get": {"operationId": "getUserLists", "tags": ["User"], "summary": "List user lists", "security": [{"cookieAuth": []}], "responses": {"200": {
        "description": "Lists with tier_max",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UserListListResponse"
            }
          }
        }
      }}},
      "post": {"operationId": "postUserLists", "tags": ["User"], "summary": "Create list", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"$ref": "#/components/parameters/CsrfHeader"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserListCreateRequest"}}}}, "responses": {"201": {
        "description": "Created",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UserListCreatedResponse"
            }
          }
        }
      }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}}}
    },
    "/api/v1/user/lists/{id}": {
      "get": {"operationId": "getUserListsById", "tags": ["User"], "summary": "Get list + items", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {
        "description": "List + items",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UserListDetail"
            }
          }
        }
      }}},
      "put": {"operationId": "putUserListsById", "tags": ["User"], "summary": "Replace mutable list fields", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserListUpdateRequest"}}}}, "responses": {"200": {
        "description": "Updated",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/OkResponse"
            }
          }
        }
      }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}, "404": {"$ref": "#/components/responses/NotFound"}}},
      "patch": {"operationId": "patchUserListsById", "tags": ["User"], "summary": "Patch mutable list fields", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserListUpdateRequest"}}}}, "responses": {"200": {
        "description": "Updated",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/OkResponse"
            }
          }
        }
      }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}, "404": {"$ref": "#/components/responses/NotFound"}}},
      "delete": {"operationId": "deleteUserListsById", "tags": ["User"], "summary": "Delete list and its items", "description": "This mutation has no request body.", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}], "responses": {"200": {
        "description": "Deleted",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/OkResponse"
            }
          }
        }
      }, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}}}
    },
    "/api/v1/user/lists/{id}/items": {
      "post": {"operationId": "postUserListsByIdItems", "tags": ["User"], "summary": "Add item to list", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserListItemCreateRequest"}}}}, "responses": {"201": {
        "description": "Added",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/OkResponse"
            }
          }
        }
      }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}, "404": {"$ref": "#/components/responses/NotFound"}}}
    },
    "/api/v1/user/lists/{id}/items/{item_id}": {
      "delete": {"operationId": "deleteUserListsByIdItemsByItemId", "tags": ["User"], "summary": "Remove item from list", "description": "This mutation has no request body.", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"name": "item_id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}], "responses": {"200": {
        "description": "Removed",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/OkResponse"
            }
          }
        }
      }, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}, "404": {"$ref": "#/components/responses/NotFound"}}}
    },
    "/api/v1/user/notes": {
      "get": {"operationId": "getUserNotes", "x-query-contract": {"allowed":["limit"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"}, "tags": ["User"], "summary": "Recent notes", "security": [{"cookieAuth": []}], "parameters": [{"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 500, "default": 50}}], "responses": {"200": {
        "description": "Notes",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UserNoteListResponse"
            }
          }
        }
      }, "400": {"$ref": "#/components/responses/BadRequest"}, "422": {"$ref": "#/components/responses/ValidationFailed"}, "401": {"$ref": "#/components/responses/Unauthorized"}}},
      "post": {"operationId": "postUserNotes", "tags": ["User"], "summary": "Create private note", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"$ref": "#/components/parameters/CsrfHeader"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserNoteCreateRequest"}}}}, "responses": {"201": {
        "description": "Created",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UserNoteCreatedResponse"
            }
          }
        }
      }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}}}
    },
    "/api/v1/user/notes/{id}": {
      "get": {"operationId": "getUserNotesById", "tags": ["User"], "summary": "Get note", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {
        "description": "Note",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UserNote"
            }
          }
        }
      }}},
      "put": {"operationId": "putUserNotesById", "tags": ["User"], "summary": "Replace mutable note fields", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserNoteUpdateRequest"}}}}, "responses": {"200": {
        "description": "Updated",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/OkResponse"
            }
          }
        }
      }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}, "404": {"$ref": "#/components/responses/NotFound"}}},
      "patch": {"operationId": "patchUserNotesById", "tags": ["User"], "summary": "Patch mutable note fields", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserNoteUpdateRequest"}}}}, "responses": {"200": {
        "description": "Updated",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/OkResponse"
            }
          }
        }
      }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}, "404": {"$ref": "#/components/responses/NotFound"}}},
      "delete": {"operationId": "deleteUserNotesById", "tags": ["User"], "summary": "Delete note", "description": "This mutation has no request body.", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}], "responses": {"200": {
        "description": "Deleted",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/OkResponse"
            }
          }
        }
      }, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}}}
    },
    "/api/v1/user/notes/for/{type}/{id}": {
      "get": {"operationId": "getUserNotesForByTypeById", "tags": ["User"], "summary": "Notes for a target", "description": "All notes about company:mercadona-sa, person:juan-perez, etc.", "security": [{"cookieAuth": []}], "parameters": [{"name": "type", "in": "path", "required": true, "schema": {"type": "string", "enum": ["company", "person", "sector", "borme_id", "free"]}}, {"name": "id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {
        "description": "Notes list",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UserNotesForTargetResponse"
            }
          }
        }
      }}}
    },
    "/api/v1/user/tags": {
      "get": {"operationId": "getUserTags", "tags": ["User"], "summary": "List user tags with counts", "security": [{"cookieAuth": []}], "responses": {"200": {
        "description": "Tags + stats",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UserTagListResponse"
            }
          }
        }
      }}},
      "post": {"operationId": "postUserTags", "tags": ["User"], "summary": "Create tag", "description": "Tier-limited account mutation.", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"$ref": "#/components/parameters/CsrfHeader"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserTagCreateRequest"}}}}, "responses": {"201": {
        "description": "Created",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UserTagCreatedResponse"
            }
          }
        }
      }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}}}
    },
    "/api/v1/user/tags/{id}": {
      "delete": {"operationId": "deleteUserTagsById", "tags": ["User"], "summary": "Delete tag and assignments", "description": "This mutation has no request body.", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}], "responses": {"200": {
        "description": "Deleted",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/OkResponse"
            }
          }
        }
      }, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}}}
    },
    "/api/v1/user/tags/{id}/assign": {
      "post": {"operationId": "postUserTagsByIdAssign", "tags": ["User"], "summary": "Assign tag to target", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserTagAssignmentRequest"}}}}, "responses": {"200": {
        "description": "Assigned",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/OkResponse"
            }
          }
        }
      }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}, "404": {"$ref": "#/components/responses/NotFound"}}}
    },
    "/api/v1/user/tags/{id}/unassign": {
      "post": {"operationId": "postUserTagsByIdUnassign", "tags": ["User"], "summary": "Unassign tag from target", "x-plane": "account", "security": [{"cookieAuth": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"$ref": "#/components/parameters/CsrfHeader"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserTagAssignmentRequest"}}}}, "responses": {"200": {
        "description": "Unassigned",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/OkResponse"
            }
          }
        }
      }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF"}, "404": {"$ref": "#/components/responses/NotFound"}}}
    },
    "/api/v1/user/exports": {
      "get": {"operationId": "getUserExports", "x-query-contract": {"allowed":["limit"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"}, "tags": ["User"], "summary": "Export history + monthly usage", "security": [{"cookieAuth": []}], "parameters": [{"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 500, "default": 50}}], "responses": {"200": {
        "description": "Recent + usage_summary {used, max, remaining, pct, unlimited}",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UserExportListResponse"
            }
          }
        }
      }, "400": {"$ref": "#/components/responses/BadRequest"}, "422": {"$ref": "#/components/responses/ValidationFailed"}, "401": {"$ref": "#/components/responses/Unauthorized"}}}
    },
    "/api/v1/user/exports/usage": {
      "get": {"operationId": "getUserExportsUsage", "tags": ["User"], "summary": "Monthly export quota usage only", "security": [{"cookieAuth": []}], "responses": {"200": {
        "description": "Usage summary",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ExportUsageResponse"
            }
          }
        }
      }}}
    },
    "/api/v1/user/audit": {
      "get": {"operationId": "getUserAudit", "x-query-contract": {"allowed":["limit","offset"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"}, "tags": ["User"], "summary": "Audit log (MAX/Enterprise only)", "description": "Returns 402 Payment Required if tier doesn't include audit_log. Retention 90d MAX, ilimitado Enterprise.", "security": [{"cookieAuth": []}], "parameters": [{"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "default": 100, "maximum": 1000}}, {"name": "offset", "in": "query", "schema": {"type": "integer", "minimum": 0, "default": 0}}], "responses": {"200": {
        "description": "Audit entries",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UserAuditResponse"
            }
          }
        }
      }, "400": {"$ref": "#/components/responses/BadRequest"}, "422": {"$ref": "#/components/responses/ValidationFailed"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "402": {"description": "Upgrade required"}}}
    },
    "/api/v1/persons/lookup": {
      "post": {
        "operationId": "lookupPersonByDni",
        "tags": ["User"],
        "summary": "Run an authenticated KYC documentary lookup",
        "description": "MAX/Enterprise account operation. Requires a declared legitimate purpose, records an audit entry and never creates a public person profile. DNI/NIE belongs only in the encrypted request body, never in URL, logs or public API surfaces.",
        "x-plane": "account",
        "x-sensitive": true,
        "security": [{"cookieAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/CsrfHeader"}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/KycPersonLookupRequest"}}}},
        "responses": {
          "200": {
            "description": "Documentary lookup result with disclaimer and usage",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KycPersonLookupResponse"
                }
              }
            }
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "402": {"description": "Plan or monthly KYC quota does not permit the lookup"},
          "403": {"description": "Invalid CSRF token"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"description": "KYC helper unavailable"}
        }
      }
    },
    "/api/v1/persons/lookup/usage": {
      "get": {
        "operationId": "getPersonLookupUsage",
        "tags": ["User"],
        "summary": "Get the caller's KYC lookup allowance and usage",
        "description": "Account-only quota metadata. It returns tier_allowed=false instead of exposing any lookup data when the plan is not eligible.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "responses": {"200": {
          "description": "KYC tier and usage metadata",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KycPersonLookupUsageResponse"
              }
            }
          }
        }, "401": {"$ref": "#/components/responses/Unauthorized"}, "503": {"description": "KYC helper unavailable"}}
      }
    },
    "/api/v1/persons/lookup/history": {
      "get": {
        "operationId": "getPersonLookupHistory",
        "x-query-contract": {"allowed":["limit","offset"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"},
        "tags": ["User"],
        "summary": "Get the caller's redacted KYC lookup history",
        "description": "Account-only, audit-derived history. Identifiers are masked/hash-backed; it is never a public people endpoint.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [
          {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 200, "default": 50}},
          {"name": "offset", "in": "query", "schema": {"type": "integer", "minimum": 0, "default": 0}}
        ],
        "responses": {"200": {
          "description": "Redacted KYC lookup history",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KycPersonLookupHistoryResponse"
              }
            }
          }
        }, "400": {"$ref": "#/components/responses/BadRequest"}, "422": {"$ref": "#/components/responses/ValidationFailed"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "402": {"description": "Plan does not include KYC lookup"}, "503": {"description": "KYC helper unavailable"}}
      }
    },
    "/api/v1/user/api-credentials": {
      "get": {
        "operationId": "listUserApiCredentials",
        "x-query-contract": {"allowed":["limit","cursor"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","lexical":"400 invalid_parameter","range":"422 validation_failed"},
        "tags": ["User", "API Credentials"],
        "summary": "List API credential metadata",
        "description": "Account-plane endpoint. Revalidates the session account in users.sqlite and returns a bounded, signed-cursor page of prefixes, last four characters, scopes and lifecycle state; never a token or hash.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [
          {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 50, "default": 20}},
          {"name": "cursor", "in": "query", "description": "Opaque signed cursor bound to the authenticated user. Offset pagination is not supported.", "schema": {"type": "string", "minLength": 1, "maxLength": 256}}
        ],
        "responses": {
          "200": {"description": "Credential metadata and allowed scope catalog", "content": {"application/json": {"schema": {"type": "object", "properties": {"credentials": {"type": "array", "maxItems": 50, "items": {"$ref": "#/components/schemas/ApiCredential"}}, "allowed_scopes": {
            "type": "object",
            "description": "Scope name to human-readable capability description.",
            "maxProperties": 16,
            "additionalProperties": {
              "type": "string"
            }
          }, "token_visible_once": {"type": "boolean", "const": true}, "max_active": {"type": "integer", "const": 10}, "pagination": {"type": "object", "required": ["limit", "has_more", "next_cursor"], "properties": {"limit": {"type": "integer", "minimum": 1, "maximum": 50}, "has_more": {"type": "boolean"}, "next_cursor": {"type": ["string", "null"], "maxLength": 256}}}}}}}},
          "400": {"$ref": "#/components/responses/BadRequest"},
          "422": {"$ref": "#/components/responses/ValidationFailed"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "503": {"description": "Account, credential schema or cursor-signing service unavailable"}
        }
      },
      "post": {
        "operationId": "createUserApiCredential",
        "tags": ["User", "API Credentials"],
        "summary": "Create an API credential",
        "description": "Creates a credential once and returns the full token on the original response or an identical Idempotency-Key retry within 24 hours. Requires session cookie, X-CSRF-Token, a durable users.sqlite idempotency schema and configured credential/idempotency key material. List/get never expose the token.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [
          {"$ref": "#/components/parameters/CsrfHeader"},
          {"$ref": "#/components/parameters/AccountIdempotencyKeyHeader"}
        ],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ApiCredentialCreateRequest"}}}},
        "responses": {
          "201": {"description": "Credential created, or its encrypted one-time response replayed for the same key and payload", "headers": {"Idempotency-Replayed": {"$ref": "#/components/headers/IdempotencyReplayed"}, "Idempotency-Key-Expires": {"$ref": "#/components/headers/IdempotencyKeyExpires"}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ApiCredentialOneTimeResponse"}}}},
          "400": {"$ref": "#/components/responses/BadRequest"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "403": {"description": "Invalid CSRF token"},
          "409": {"description": "Active credential limit, Idempotency-Key payload conflict, or expired replay window"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"description": "Credential pepper, idempotency encryption keyring/schema, or account service unavailable"}
        }
      }
    },
    "/api/v1/user/api-credentials/{id}/rotate": {
      "post": {
        "operationId": "rotateUserApiCredential",
        "tags": ["User", "API Credentials"],
        "summary": "Rotate one API credential",
        "description": "Atomically revokes the source and stores the encrypted one-time replacement response with the same transaction. An identical Idempotency-Key retry within 24 hours returns the same token without rotating again.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [
          {"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}},
          {"$ref": "#/components/parameters/CsrfHeader"},
          {"$ref": "#/components/parameters/AccountIdempotencyKeyHeader"}
        ],
        "requestBody": {"required": false, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ApiCredentialRotateRequest"}}}},
        "responses": {
          "200": {"description": "Rotated, or the exact replacement token replayed for the same key and payload", "headers": {"Idempotency-Replayed": {"$ref": "#/components/headers/IdempotencyReplayed"}, "Idempotency-Key-Expires": {"$ref": "#/components/headers/IdempotencyKeyExpires"}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ApiCredentialOneTimeResponse"}}}},
          "400": {"$ref": "#/components/responses/BadRequest"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "403": {"description": "Invalid CSRF token"},
          "404": {"$ref": "#/components/responses/NotFound"},
          "409": {"description": "Idempotency-Key payload conflict or expired replay window"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"description": "Credential pepper, idempotency encryption keyring/schema, or account service unavailable"}
        }
      }
    },
    "/api/v1/user/api-credentials/{id}": {
      "delete": {
        "operationId": "revokeUserApiCredential",
        "tags": ["User", "API Credentials"],
        "summary": "Revoke one API credential",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [
          {"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}},
          {"name": "X-CSRF-Token", "in": "header", "required": true, "schema": {"type": "string"}}
        ],
        "responses": {
          "200": {
            "description": "Credential revoked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CredentialRevokedResponse"
                }
              }
            }
          },
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "403": {"description": "Invalid CSRF token"},
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"description": "Account security or credential schema unavailable"}
        }
      }
    },
    "/api/v1/user/webhooks": {
      "get": {
        "operationId": "listUserWebhooks",
        "tags": ["User", "Webhooks"],
        "summary": "List outbound webhook metadata",
        "description": "Account-plane metadata, the exact payload-contract 1.0 event allowlist and worker health. Full signing secrets are never listed; signing secrets are encrypted at rest with a versioned keyring. Unknown event types and schema versions fail closed.",
        "x-webhook-event-contract-version": "1.0",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "responses": {
          "200": {"description": "Webhook metadata", "content": {"application/json": {"schema": {"type": "object", "properties": {"webhooks": {"type": "array", "items": {"$ref": "#/components/schemas/OutboundWebhook"}}, "allowed_events": {"$ref": "#/components/schemas/OutboundWebhookEventCatalogV1"}, "contracted_events": {"$ref": "#/components/schemas/OutboundWebhookContractedEventCatalogV1"}, "worker": {"$ref": "#/components/schemas/WebhookWorkerHealth"}, "secret_visible_once": {"type": "boolean", "const": true}}}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "503": {"description": "Account or webhook security schema unavailable"}
        }
      },
      "post": {
        "operationId": "createUserWebhook",
        "tags": ["User", "Webhooks"],
        "summary": "Create an outbound webhook",
        "description": "Validates HTTPS destination against SSRF, accepts only the explicit payload-contract 1.0 event allowlist, and atomically stores both the encrypted signing secret and an encrypted 24-hour idempotency replay. An identical Idempotency-Key retry returns the same secret without creating a second webhook. Wildcards and unknown events fail closed with 400.",
        "x-webhook-event-contract-version": "1.0",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [
          {"$ref": "#/components/parameters/CsrfHeader"},
          {"$ref": "#/components/parameters/AccountIdempotencyKeyHeader"}
        ],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/OutboundWebhookCreateRequest"}}}},
        "responses": {
          "201": {"description": "Created, or the exact signing secret replayed for the same key and payload", "headers": {"Idempotency-Replayed": {"$ref": "#/components/headers/IdempotencyReplayed"}, "Idempotency-Key-Expires": {"$ref": "#/components/headers/IdempotencyKeyExpires"}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/OutboundWebhookOneTimeResponse"}}}},
          "400": {"$ref": "#/components/responses/BadRequest"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "403": {"description": "Invalid CSRF token"},
          "409": {"description": "Idempotency-Key payload conflict or expired replay window"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"description": "Webhook service, secret keyring, or durable idempotency schema/keyring unavailable"}
        }
      }
    },
    "/api/v1/user/webhooks/{id}": {
      "patch": {
        "operationId": "updateUserWebhook",
        "tags": ["User", "Webhooks"],
        "summary": "Update an outbound webhook",
        "description": "Revalidates URL/DNS/SSRF on every destination change and accepts only payload-contract 1.0 event types. Wildcards and unknown events fail closed with 400. The secret is not returned.",
        "x-webhook-event-contract-version": "1.0",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [
          {"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}},
          {"name": "X-CSRF-Token", "in": "header", "required": true, "schema": {"type": "string"}}
        ],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/OutboundWebhookUpdateRequest"}}}},
        "responses": {"200": {
          "description": "Updated metadata",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookUpdatedResponse"
              }
            }
          }
        }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF token"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"description": "Account security or webhook schema unavailable"}}
      },
      "delete": {
        "operationId": "deleteUserWebhook",
        "tags": ["User", "Webhooks"],
        "summary": "Delete an outbound webhook",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [
          {"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}},
          {"name": "X-CSRF-Token", "in": "header", "required": true, "schema": {"type": "string"}}
        ],
        "responses": {"200": {
          "description": "Deleted",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeletedResponse"
              }
            }
          }
        }, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF token"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"description": "Account security or webhook schema unavailable"}}
      }
    },
    "/api/v1/user/webhooks/{id}/rotate": {
      "post": {
        "operationId": "rotateUserWebhookSecret",
        "tags": ["User", "Webhooks"],
        "summary": "Rotate an outbound webhook signing secret",
        "description": "Cancels pending deliveries signed with the old key and atomically stores the encrypted replacement response. An identical Idempotency-Key retry within 24 hours returns the same secret without rotating again.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [
          {"name": "id", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1}},
          {"$ref": "#/components/parameters/CsrfHeader"},
          {"$ref": "#/components/parameters/AccountIdempotencyKeyHeader"}
        ],
        "responses": {
          "200": {"description": "Rotated, or the exact replacement signing secret replayed for the same key", "headers": {"Idempotency-Replayed": {"$ref": "#/components/headers/IdempotencyReplayed"}, "Idempotency-Key-Expires": {"$ref": "#/components/headers/IdempotencyKeyExpires"}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/OutboundWebhookOneTimeResponse"}}}},
          "400": {"$ref": "#/components/responses/BadRequest"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "403": {"description": "Invalid CSRF token"},
          "404": {"$ref": "#/components/responses/NotFound"},
          "409": {"description": "Idempotency-Key payload conflict or expired replay window"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"description": "Account security, encryption keyring or webhook schema unavailable"}
        }
      }
    },
    "/api/v1/support/ticket": {
      "post": {
        "operationId": "createSupportTicket",
        "tags": ["Support"],
        "summary": "Create a customer-support ticket",
        "description": "Public write exception for customer support. Authentication is optional, but the boolean `accept_privacy=true` is mandatory and is persisted as the purpose-bound audit event `privacy_accepted` / `privacy_policy_v1`. The submitted contact details, message, client IP and a user-agent capped by the runtime are stored in the account database solely to process, audit and protect the support request; ticket contents are never public or available to the public MCP. Related context accepts only a validated company slug and a local or canonical-origin OpenMercantil URL, which is stored as text and never dereferenced. The JSON body is capped at 32 KiB.",
        "x-plane": "account-support",
        "x-max-body-bytes": 32768,
        "x-rate-limit": "API plan policy plus an anti-abuse ceiling of 5 creations per client IP per hour",
        "x-mcp-excluded": true,
        "security": [{}, {"cookieAuth": []}],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {"$ref": "#/components/schemas/SupportTicketCreateRequest"}
            }
          }
        },
        "responses": {
          "201": {
            "description": "Ticket created; only its internal numeric id and non-secret public reference are returned",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SupportTicketCreatedResponse"}}}
          },
          "400": {
            "description": "Invalid JSON fields, validation failure or missing strict privacy consent",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SupportRequestErrorResponse"}}}
          },
          "413": {
            "description": "Request body exceeds 32 KiB",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RequestBodyTooLargeError"}, "example": {"error": "request_body_too_large", "max_bytes": 32768}}}
          },
          "429": {
            "description": "API plan quota exhausted or the per-IP ceiling of 5 ticket creations per hour was reached",
            "headers": {"Retry-After": {"description": "Seconds before retrying", "schema": {"type": "integer", "minimum": 1}}},
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SupportRequestErrorResponse"}}}
          },
          "503": {
            "description": "The account database or migrated support schema is unavailable; creation fails closed",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SupportErrorResponse"}, "example": {"ok": false, "error": "Servicio no disponible."}}}
          }
        }
      }
    },
    "/api/v1/support/ticket/{id}/reply": {
      "post": {
        "operationId": "replySupportTicket",
        "tags": ["Support", "User"],
        "summary": "Reply to a support ticket owned by the authenticated user",
        "description": "Requires a fresh account session, `X-CSRF-Token`, ownership of the numeric ticket id and a non-closed ticket. The reply is persisted before best-effort notification. The JSON body is capped at 32 KiB and ticket contents are never exposed through the public MCP.",
        "x-plane": "account-support",
        "x-max-body-bytes": 32768,
        "x-rate-limit": "API plan policy plus a per-user action budget of 20 replies per 15 minutes and 100 per day",
        "x-mcp-excluded": true,
        "security": [{"cookieAuth": []}],
        "parameters": [
          {"name": "id", "in": "path", "required": true, "description": "Internal ticket id; ownership is revalidated server-side.", "schema": {"type": "integer", "minimum": 1}},
          {"$ref": "#/components/parameters/CsrfHeader"}
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {"$ref": "#/components/schemas/SupportReplyRequest"}
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reply persisted",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/OkResponse"}, "example": {"ok": true}}}
          },
          "400": {
            "description": "Reply validation failed or the ticket is closed",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SupportRequestErrorResponse"}}}
          },
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "403": {
            "description": "Invalid CSRF token, ticket not found under this account, or caller is not the owner",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SupportErrorResponse"}}}
          },
          "413": {
            "description": "Request body exceeds 32 KiB",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RequestBodyTooLargeError"}, "example": {"error": "request_body_too_large", "max_bytes": 32768}}}
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {
            "description": "The action-budget store, account database or migrated support schema is unavailable; reply fails closed",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SupportRequestErrorResponse"}, "example": {"ok": false, "error": "Servicio no disponible."}}}
          }
        }
      }
    },
    "/api/v1/csrf": {
      "get": {
        "operationId": "getCsrfToken",
        "tags": ["User"],
        "summary": "Get a live same-origin CSRF token",
        "description": "Returns the token for the caller's current browser session and whether it is authenticated. The response is private and never cacheable.",
        "x-plane": "account",
        "security": [],
        "responses": {
          "200": {"description": "Session CSRF state", "content": {"application/json": {"schema": {"type": "object", "properties": {"csrf": {"type": "string"}, "logged_in": {"type": "boolean"}}}}}}
        }
      }
    },
    "/api/v1/resend-verification": {
      "post": {
        "operationId": "postResendVerification",
        "tags": ["User"],
        "summary": "Resend the account email-verification link",
        "description": "Rate-limited before database and mail work. A new purpose-bound token is stored only as a hash.",
        "x-plane": "account",
        "security": [{"cookieAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/CsrfHeader"}],
        "responses": {"200": {
          "description": "Verification email accepted by transport",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerificationDispatchResponse"
              }
            }
          }
        }, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF token"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "502": {"description": "Mail transport unavailable"}}
      }
    },
    "/api/v1/donation": {
      "post": {
        "operationId": "postDonationCheckout",
        "tags": ["Billing"],
        "summary": "Create a one-time donation Checkout session",
        "description": "Anonymous or authenticated. Body is capped at 16 KiB; Stripe work is fail-closed, budgeted by trusted client IP and idempotent within a 15-minute retry window. A supplied idempotency key is hashed and namespaced before Stripe.",
        "x-plane": "billing",
        "security": [],
        "parameters": [{"name": "Idempotency-Key", "in": "header", "required": false, "schema": {"type": "string", "pattern": "^[A-Za-z0-9._:\\-]{8,200}$"}}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "additionalProperties": false, "required": ["amount_cents"], "properties": {"amount_cents": {"type": "integer", "minimum": 100, "maximum": 100000}, "message": {"type": "string", "maxLength": 500}, "idempotency_key": {"type": "string", "pattern": "^[A-Za-z0-9._:\\-]{8,200}$"}}}}}},
        "responses": {"200": {
          "description": "Checkout URL and Stripe session id",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StripeSessionResponse"
              }
            }
          }
        }, "400": {"$ref": "#/components/responses/BadRequest"}, "413": {"description": "Request body too large"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"description": "Action budget or Stripe unavailable"}}
      }
    },
    "/api/v1/credits/checkout": {
      "post": {
        "operationId": "postCreditsCheckout",
        "tags": ["Billing", "User"],
        "summary": "Create an idempotent credit-pack Checkout session",
        "description": "Requires login and CSRF. The body is capped at 16 KiB and every external attempt consumes a strict per-user budget.",
        "x-plane": "billing",
        "security": [{"cookieAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/CsrfHeader"}, {"name": "Idempotency-Key", "in": "header", "required": false, "schema": {"type": "string", "pattern": "^[A-Za-z0-9._:\\-]{8,200}$"}}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "additionalProperties": false, "required": ["pack"], "properties": {"pack": {"type": "string", "enum": ["pack_250", "pack_600", "pack_1500", "pack_4000"]}, "csrf": {"type": "string"}, "idempotency_key": {"type": "string", "pattern": "^[A-Za-z0-9._:\\-]{8,200}$"}}}}}},
        "responses": {"200": {
          "description": "Checkout URL and Stripe session id",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StripeSessionResponse"
              }
            }
          }
        }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF token"}, "413": {"description": "Request body too large"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"description": "Action budget or Stripe unavailable"}}
      }
    },
    "/api/v1/empresa/{slug}/informe-legal": {
      "post": {
        "operationId": "createCompanyLegalReport",
        "tags": ["Legal", "Companies", "User"],
        "summary": "Create the authenticated user's redacted corporate legal report",
        "description": "Account and credit-entitlement surface for a legal entity only. The server owns beta/pricing policy and a daily idempotency key scoped to user, company and UTC date; clients cannot choose price or entitlement. Every report is recursively PII-redacted before egress. Documentary events and citations do not prove wrongdoing, solvency, current status, identity of a natural person or completeness, and this informational report is not legal advice or an official certificate. Unknown or unauthorized source policy, natural-person subjects and missing helpers fail closed. The JSON body is capped at 32 KiB and accepts only the CSRF fallback.",
        "x-plane": "account-paid-egress",
        "x-entitlement": "legal_report (server-owned credits/beta policy)",
        "x-source-policy": "legal_report_v1; fail closed until a versioned public decision authorizes every included source",
        "x-activation-status": "policy-closed",
        "x-idempotency-key": "server: legal_report:{user_id}:{company_slug}:{UTC-date}",
        "x-max-body-bytes": 32768,
        "x-rate-limit": "API plan policy plus a per-user action budget of 10 attempts per 15 minutes and 50 per day",
        "x-privacy": "Corporate subjects only; recursive PII redaction before serialization",
        "x-mcp-excluded": true,
        "security": [{"cookieAuth": []}],
        "parameters": [
          {"name": "slug", "in": "path", "required": true, "schema": {"type": "string", "pattern": "^[a-z0-9-]+$"}},
          {"$ref": "#/components/parameters/CsrfHeader"}
        ],
        "requestBody": {
          "required": false,
          "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LegalReportRequest"}}}
        },
        "responses": {
          "200": {
            "description": "Redacted documentary corporate report and server-owned charging result",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LegalReportResponse"}}}
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "402": {
            "description": "Insufficient credits or the idempotent charge could not be completed",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LegalReportPaymentRequiredError"}}}
          },
          "403": {"description": "Invalid or missing CSRF token", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}},
          "404": {
            "description": "Corporate subject not found or the slug is classified as a natural-person subject",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": "not_found"}}}
          },
          "413": {
            "description": "Request body exceeds 32 KiB",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RequestBodyTooLargeError"}, "example": {"error": "request_body_too_large", "max_bytes": 32768}}}
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {
            "description": "Action-budget storage, legal source policy, report helper, account schema or credit ledger unavailable; generation fails closed",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}
          }
        }
      }
    },
    "/api/v1/checkout": {
      "post": {
        "operationId": "postSubscriptionCheckout",
        "tags": ["Billing", "User"],
        "summary": "Create a subscription Checkout session",
        "description": "Requires a Secure, SameSite browser session and X-CSRF-Token. Trial policy is server-owned: clients cannot send trial_days or no_default_trial. Idempotency is scoped to user, plan and billing period before Stripe.",
        "x-plane": "billing",
        "security": [{"cookieAuth": []}],
        "parameters": [
          {
            "$ref": "#/components/parameters/CsrfHeader"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._:\\-]{8,200}$"
            }
          }
        ],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "additionalProperties": false, "required": ["plan"], "properties": {"plan": {"type": "string", "enum": ["profesional", "max", "pro", "business", "agency"]}, "billing": {"type": "string", "enum": ["monthly", "yearly", "anual"], "default": "monthly"}, "coupon": {"type": "string", "maxLength": 80}, "csrf": {"type": "string", "description": "Body fallback accepted by the runtime; prefer X-CSRF-Token."}, "idempotency_key": {"type": "string", "pattern": "^[A-Za-z0-9._:\\-]{8,200}$"}}}}}},
        "responses": {
          "200": {
            "description": "Checkout URL and Stripe session id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StripeSessionResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "413": {
            "description": "Request body too large"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {
            "description": "Action budget or Stripe unavailable"
          },
          "403": {
            "description": "Invalid CSRF token"
          }
        }
      }
    },
    "/api/v1/billing/invoices": {
      "get": {
        "operationId": "getBillingInvoices",
        "tags": ["Billing", "User"],
        "summary": "List the authenticated user's invoices and subscription",
        "x-plane": "billing",
        "security": [{"cookieAuth": []}],
        "responses": {"200": {
          "description": "Local billing projection",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BillingInvoicesResponse"
              }
            }
          }
        }, "401": {"$ref": "#/components/responses/Unauthorized"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}
      }
    },
    "/api/v1/billing/portal": {
      "get": {
        "operationId": "getBillingPortal",
        "tags": ["Billing", "User"],
        "summary": "Redirect to the authenticated user's Stripe portal",
        "x-plane": "billing",
        "security": [{"cookieAuth": []}],
        "responses": {"302": {"description": "Redirect to Stripe Customer Portal"}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"description": "Action budget or Stripe unavailable"}}
      },
      "post": {
        "operationId": "postBillingPortal",
        "tags": ["Billing", "User"],
        "summary": "Create a Stripe portal session as JSON",
        "x-plane": "billing",
        "security": [{"cookieAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/CsrfHeader"}],
        "responses": {"200": {
          "description": "Stripe Customer Portal URL",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StripeSessionResponse"
              }
            }
          }
        }, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "Invalid CSRF token"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"description": "Action budget or Stripe unavailable"}}
      }
    },
    "/api/v1/portal": {
      "post": {
        "operationId": "postLegacyBillingPortal",
        "tags": ["Billing", "User"],
        "summary": "Create a Stripe Customer Portal session through the legacy alias",
        "description": "Deprecated alias of `POST /api/v1/billing/portal`. Requires an authenticated browser session and a valid CSRF token supplied either in `X-CSRF-Token` or the form field `csrf`. New clients must use the canonical billing route.",
        "deprecated": true,
        "x-replaced-by": "/api/v1/billing/portal",
        "x-plane": "billing",
        "x-rate-limit": "Per-user action budget: 5 attempts per 15 minutes and 30 per day",
        "x-mcp-excluded": true,
        "security": [{"cookieAuth": []}],
        "parameters": [
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": false,
            "description": "Required unless the same token is sent in the form field `csrf`.",
            "schema": {"type": "string", "minLength": 32, "maxLength": 256}
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Legacy form fallback for CSRF. Prefer the header and an empty body.",
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {"csrf": {"type": "string", "minLength": 32, "maxLength": 256}}
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stripe Customer Portal URL",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StripeSessionResponse"}}}
          },
          "400": {"$ref": "#/components/responses/BadRequest"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "403": {"description": "Invalid or missing CSRF token", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"description": "Action-budget storage or Stripe Customer Portal is unavailable", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}
        }
      }
    },
    "/api/v1/stripe-webhook": {
      "post": {
        "operationId": "receiveStripeWebhook",
        "tags": ["Billing", "Integrations"],
        "summary": "Receive a signed Stripe event",
        "description": "Provider callback, not an end-user API. The exact raw JSON body is capped at 512 KiB and verified against `Stripe-Signature` before durable inbox claim or side effects. Provider `event.id` supplies idempotency; terminal duplicates return 200, active leases return 503 for retry, and failures return 500 so Stripe retries. No webhook secret, signature, raw payload or internal exception is returned. This route is excluded from every public MCP surface.",
        "x-plane": "integration-provider-callback",
        "x-provider": "stripe",
        "x-max-body-bytes": 524288,
        "x-idempotency-key": "Stripe event.id",
        "x-log-policy": "Redact Stripe-Signature and the raw request body",
        "x-mcp-excluded": true,
        "security": [],
        "parameters": [
          {
            "name": "Stripe-Signature",
            "in": "header",
            "required": true,
            "description": "Stripe-generated signature verified over the exact raw body. It is sensitive request metadata and must never be logged or echoed.",
            "schema": {"type": "string", "minLength": 1}
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {"$ref": "#/components/schemas/StripeWebhookEventRequest"}
            }
          }
        },
        "responses": {
          "200": {
            "description": "Event accepted, deliberately ignored, or already terminal. All response bodies are non-secret acknowledgements.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "enum": ["ok", "duplicate (terminal idempotent skip)", "ignored (other source)", "credits ok", "donation ok", "subscription missing", "historical subscription ignored", "clawback rejected", "clawback", "ignored", "ignored invoice", "ignored payment failure"]
                }
              }
            }
          },
          "400": {
            "description": "Signature missing/invalid, or the raw request stream cannot be read",
            "content": {
              "text/plain": {"schema": {"type": "string", "const": "Bad signature"}},
              "application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": "request_body_unreadable"}}
            }
          },
          "413": {
            "description": "Raw callback body exceeds 512 KiB",
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RequestBodyTooLargeError"}, "example": {"error": "request_body_too_large", "max_bytes": 524288}}}
          },
          "500": {
            "description": "Inbox persistence or event processing failed; Stripe must retry",
            "content": {"text/plain": {"schema": {"type": "string", "enum": ["webhook inbox unavailable", "error"]}}}
          },
          "503": {
            "description": "Another worker owns an active lease or a signed OpenMercantil checkout cannot yet be resolved to its authoritative account owner; Stripe must retry",
            "headers": {"Retry-After": {"description": "Retry delay in seconds", "schema": {"type": "integer", "const": 5}}},
            "content": {"text/plain": {"schema": {"type": "string", "enum": ["event already processing", "credits owner unavailable", "subscription owner unavailable"]}}}
          }
        }
      }
    },
    "/api/v1/legal/norms": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "legal:read",
        "operationId": "getLegalNorms",
        "tags": ["Legal"],
        "summary": "Index of core Spanish mercantile-law norms",
        "description": "Return the catalog of core Spanish mercantile-law norms (codes, laws, royal-decree-legislatives, regulations) structured by OpenMercantil. Each item links to its HTML page (`/ley/{slug}`) and its norm-detail API (`/api/v1/legal/norm/{slug}`). LICENSE: consolidated text from the BOE, re-used under Ley 37/2007; the official, authentic version is always boe.es. Informational only — NOT legal advice. Cached 24h. Returns 503 if the legal catalog is not deployed yet.",
        "x-rate-limit": "free 60/min · 200/day",
        "x-license": "BOE — Ley 37/2007 (re-use of public sector information)",
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "Norm index with license/attribution/disclaimer envelope",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/LegalNormsIndexResponse"},
                "example": {
                  "layer": "derecho-mercantil",
                  "count": 48,
                  "norms": [
                    {
                      "slug": "ley-de-sociedades-de-capital",
                      "title": "Ley de Sociedades de Capital (texto refundido, RDLeg 1/2010)",
                      "short_name": "LSC",
                      "norm_type": "real_decreto_legislativo",
                      "norm_type_label": "Real Decreto Legislativo",
                      "in_force": true,
                      "url": "https://openmercantil.es/ley/ley-de-sociedades-de-capital",
                      "api_url": "https://openmercantil.es/api/v1/legal/norm/ley-de-sociedades-de-capital"
                    }
                  ],
                  "license": "BOE — Ley 37/2007 (reutilización de la información del sector público)",
                  "license_url": "https://www.boe.es/informacion/aviso_legal/index.php",
                  "attribution": "Texto consolidado del Boletín Oficial del Estado (BOE), estructurado por OpenMercantil. La versión oficial y auténtica es la publicada en boe.es.",
                  "disclaimer": "Contenido meramente informativo. No constituye asesoramiento jurídico ni sustituye al texto oficial consolidado del BOE.",
                  "docs": "https://openmercantil.es/leyes",
                  "generated_at": "2026-06-04T00:00:00+00:00"
                }
              }
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/legal/norm": {
      "get": {
        "operationId": "getLegacyLegalNorms",
        "tags": ["Legal"],
        "summary": "Index mercantile-law norms through the singular legacy alias",
        "description": "Deprecated alias of `GET /api/v1/legal/norms`. It returns the same BOE-attributed informational catalog and is not the norm-detail route; norm detail requires `/api/v1/legal/norm/{slug}`.",
        "deprecated": true,
        "x-replaced-by": "/api/v1/legal/norms",
        "x-rate-limit": "free 60/min · 200/day",
        "x-license": "BOE — Ley 37/2007 (re-use of public sector information)",
        "responses": {
          "200": {"description": "Norm index with license, attribution and disclaimer envelope", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LegalNormsIndexResponse"}}}},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/legal/norm/{slug}": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "legal:read",
        "operationId": "getLegalNormBySlug",
        "tags": ["Legal"],
        "summary": "Detail of a single mercantile-law norm (with act↔norm bridge)",
        "description": "Return one norm's BOE/ELI identification, its key articles (each with canonical URL + a flag for seeded consolidated text), the BORME act types it governs (the law→data bridge) and a single AI-citable atomic fact (`citable_fact`). LICENSE: consolidated text from the BOE, re-used under Ley 37/2007; the official version is boe.es. Informational only — NOT legal advice. Cached 24h.",
        "x-rate-limit": "free 60/min · 200/day",
        "x-license": "BOE — Ley 37/2007 (re-use of public sector information)",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {"type": "string", "pattern": "^[a-z0-9\\-]+$", "example": "ley-de-sociedades-de-capital"},
            "description": "Norm slug as listed by /api/v1/legal/norms."
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "Norm detail with key articles, regulated acts and a citable fact",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/LegalNormResponse"},
                "example": {
                  "norm": {
                    "slug": "ley-de-sociedades-de-capital",
                    "title": "Ley de Sociedades de Capital (texto refundido, RDLeg 1/2010)",
                    "short_name": "LSC",
                    "norm_type": "real_decreto_legislativo",
                    "norm_type_label": "Real Decreto Legislativo",
                    "boe_id": "BOE-A-2010-10544",
                    "eli": "https://www.boe.es/eli/es/rdlg/2010/07/02/1",
                    "official_url": "https://www.boe.es/buscar/act.php?id=BOE-A-2010-10544",
                    "in_force": true,
                    "repealed_by": null,
                    "summary": "Norma central del derecho societario español: regula la sociedad anónima (SA), la limitada (SL/SLU) y la comanditaria por acciones.",
                    "date_published": "2010-07-02",
                    "date_modified": "2026-06-04",
                    "url": "https://openmercantil.es/ley/ley-de-sociedades-de-capital"
                  },
                  "key_articles": [
                    {
                      "article_num": "318",
                      "label": "El acuerdo de reducción del capital social",
                      "rule": "la reducción del capital social habrá de acordarse por la junta general con los requisitos de la modificación de estatutos",
                      "has_text": true,
                      "url": "https://openmercantil.es/ley/ley-de-sociedades-de-capital/articulo/318",
                      "api_url": "https://openmercantil.es/api/v1/legal/article/ley-de-sociedades-de-capital/318"
                    }
                  ],
                  "regulated_acts": [
                    {
                      "act_type": "ampliacion-capital",
                      "label": "Ampliación de capital",
                      "articles": "LSC arts. 295-316",
                      "microtext": "El aumento de capital social está regulado en los arts. 295-316 LSC.",
                      "url": "https://openmercantil.es/ley/ley-de-sociedades-de-capital/empresas"
                    }
                  ],
                  "citable_fact": {
                    "statement": "La reducción del capital social de una SA o SL debe acordarse por la junta general con los requisitos de la modificación de estatutos (art. 318 LSC).",
                    "source": "BOE — texto consolidado (Ley 37/2007)",
                    "source_url": "https://www.boe.es/buscar/act.php?id=BOE-A-2010-10544",
                    "date": "2010-07-02",
                    "verify_url": "https://openmercantil.es/ley/ley-de-sociedades-de-capital/articulo/318"
                  },
                  "license": "BOE — Ley 37/2007 (reutilización de la información del sector público)",
                  "license_url": "https://www.boe.es/informacion/aviso_legal/index.php",
                  "attribution": "Texto consolidado del Boletín Oficial del Estado (BOE), estructurado por OpenMercantil. La versión oficial y auténtica es la publicada en boe.es.",
                  "disclaimer": "Contenido meramente informativo. No constituye asesoramiento jurídico ni sustituye al texto oficial consolidado del BOE.",
                  "generated_at": "2026-06-04T00:00:00+00:00"
                }
              }
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/legal/article/{norm}/{n}": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "legal:read",
        "operationId": "getLegalArticleByNormByN",
        "tags": ["Legal"],
        "summary": "Consolidated text of a single article",
        "description": "Return the consolidated text (`body_html`) of one article of a norm, plus its ELI anchor, version date and the minimal context of the parent norm. The text comes from the consolidated BOE and is re-used under Ley 37/2007 — the official version is boe.es. Informational only — NOT legal advice. Cached 24h. The article number `{n}` accepts digits plus a bis/ter suffix joined by a hyphen (e.g. `160-bis`).",
        "x-rate-limit": "free 60/min · 200/day",
        "x-license": "BOE — Ley 37/2007 (re-use of public sector information)",
        "parameters": [
          {
            "name": "norm",
            "in": "path",
            "required": true,
            "schema": {"type": "string", "pattern": "^[a-z0-9\\-]+$", "example": "ley-de-sociedades-de-capital"},
            "description": "Norm slug."
          },
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {"type": "string", "pattern": "^[0-9a-z\\-\\.]+$", "example": "318"},
            "description": "Article number (digits, optionally with a bis/ter suffix joined by a hyphen)."
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "Consolidated article text",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/LegalArticleResponse"},
                "example": {
                  "norm": {
                    "slug": "ley-de-sociedades-de-capital",
                    "title": "Ley de Sociedades de Capital (texto refundido, RDLeg 1/2010)",
                    "short_name": "LSC",
                    "official_url": "https://www.boe.es/buscar/act.php?id=BOE-A-2010-10544"
                  },
                  "article_num": "318",
                  "title": "Artículo 318. El acuerdo de reducción del capital social.",
                  "body_html": "<p>1. La reducción del capital social habrá de acordarse por la junta general con los requisitos de la modificación de estatutos.</p>",
                  "eli_anchor": "https://www.boe.es/eli/es/rdlg/2010/07/02/1/con#a318",
                  "version_date": "2021-01-01",
                  "url": "https://openmercantil.es/ley/ley-de-sociedades-de-capital/articulo/318",
                  "license": "BOE — Ley 37/2007 (reutilización de la información del sector público)",
                  "license_url": "https://www.boe.es/informacion/aviso_legal/index.php",
                  "attribution": "Texto consolidado del Boletín Oficial del Estado (BOE), estructurado por OpenMercantil. La versión oficial y auténtica es la publicada en boe.es.",
                  "disclaimer": "Contenido meramente informativo. No constituye asesoramiento jurídico ni sustituye al texto oficial consolidado del BOE.",
                  "generated_at": "2026-06-04T00:00:00+00:00"
                }
              }
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/legal/act-map": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "legal:read",
        "operationId": "getLegalActMap",
        "tags": ["Legal"],
        "summary": "BORME act type → governing norm bridge (full or single)",
        "description": "Return the bridge mapping each BORME act type (constitución, nombramiento, ampliación de capital, disolución, concurso, …) to the norm and articles that govern it — the law↔data connection that lets an LLM answer 'which law governs this registry act'. Without `{acto}` returns the full map; with `/act-map/{acto}` returns a single mapping. License: BOE / Ley 37/2007. Informational only — NOT legal advice. Cached 24h.",
        "x-rate-limit": "free 60/min · 200/day",
        "x-license": "BOE — Ley 37/2007 (re-use of public sector information)",
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "Full act→norm map with license envelope",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/LegalActMapResponse"},
                "example": {
                  "layer": "puente-acto-norma",
                  "count": 22,
                  "act_map": [
                    {
                      "act_type": "ampliacion-capital",
                      "norm_slug": "ley-de-sociedades-de-capital",
                      "norm_api_url": "https://openmercantil.es/api/v1/legal/norm/ley-de-sociedades-de-capital",
                      "articles": "LSC arts. 295-316",
                      "microtext": "El aumento de capital social está regulado en los arts. 295-316 LSC.",
                      "concept_slug": null
                    }
                  ],
                  "license": "BOE — Ley 37/2007 (reutilización de la información del sector público)",
                  "license_url": "https://www.boe.es/informacion/aviso_legal/index.php",
                  "attribution": "Texto consolidado del Boletín Oficial del Estado (BOE), estructurado por OpenMercantil. La versión oficial y auténtica es la publicada en boe.es.",
                  "disclaimer": "Contenido meramente informativo. No constituye asesoramiento jurídico ni sustituye al texto oficial consolidado del BOE.",
                  "generated_at": "2026-06-04T00:00:00+00:00"
                }
              }
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/legal/act-map/{acto}": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "legal:read",
        "operationId": "getLegalActMapByActo",
        "tags": ["Legal"],
        "summary": "Governing norm for a single BORME act type",
        "description": "Return the norm + articles that govern a single BORME act type. License: BOE / Ley 37/2007. Informational only — NOT legal advice.",
        "x-rate-limit": "free 60/min · 200/day",
        "x-license": "BOE — Ley 37/2007 (re-use of public sector information)",
        "parameters": [
          {
            "name": "acto",
            "in": "path",
            "required": true,
            "schema": {"type": "string", "pattern": "^[a-z0-9\\-]+$", "example": "ampliacion-capital"},
            "description": "BORME act type slug (as listed in the full act-map)."
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },
            "description": "Single act→norm mapping",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/LegalActMapEntry"},
                "example": {
                  "act_type": "ampliacion-capital",
                  "norm_slug": "ley-de-sociedades-de-capital",
                  "norm_api_url": "https://openmercantil.es/api/v1/legal/norm/ley-de-sociedades-de-capital",
                  "articles": "LSC arts. 295-316",
                  "microtext": "El aumento de capital social está regulado en los arts. 295-316 LSC.",
                  "concept_slug": null,
                  "license": "BOE — Ley 37/2007 (reutilización de la información del sector público)",
                  "license_url": "https://www.boe.es/informacion/aviso_legal/index.php",
                  "attribution": "Texto consolidado del Boletín Oficial del Estado (BOE), estructurado por OpenMercantil. La versión oficial y auténtica es la publicada en boe.es.",
                  "disclaimer": "Contenido meramente informativo. No constituye asesoramiento jurídico ni sustituye al texto oficial consolidado del BOE.",
                  "generated_at": "2026-06-04T00:00:00+00:00"
                }
              }
            }
          },
          "404": {"$ref": "#/components/responses/NotFound"},
          "429": {"$ref": "#/components/responses/TooManyRequests"},
          "503": {"$ref": "#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/tenders": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "tenders:read",
        "operationId": "searchTenders",
        "tags": ["Public Procurement"],
        "summary": "Search public procurement notices",
        "description": "Cursor-paginated PLACSP notice search over the materialized legal-first projection. The query contract is closed-world and scalar: unknown names, arrays and lexical type mismatches return 400; validly typed values outside documented ranges return 422. Full-text query indexes notice object and buyer only; it never indexes supplier names. Full-text plus structured filters returns 422 until a compound offline projection exists. CPV accepts an indexed 2-8 digit prefix, may combine only with published_from/published_to, and returns 503 rather than falling back when its CPV-date projection or exact index is unavailable. supplier_cif is resolved by the generation-bound offline 0062 projection and matches either the notice's top-level corporate adjudicatario or any materialized corporate coadjudicator. It may combine with phase, buyer_nif, province and publication dates; open_only and every monetary filter require a future compound projection and return 422. Because one notice can have several adjudicators, a search summary may display a different admitted top-level supplier; tender detail retains the complete materialized result set. Natural-person supplier names and identifiers are withheld together. Budget, estimated value and award are separate source-reported fields and none proves paid or executed spend. open_only freezes one UTC date for SQL filtering, row is_open semantics and cursor binding.",
        "x-data-source": "PLACSP",
        "x-privacy": "Natural-person and uncertain buyer/supplier identity is withheld. buyer_nif and supplier_cif accept entity identifiers only.",
        "x-performance-budget-ms": 200,
        "x-query-contract": {"allowed":["q","cpv","phase","province","buyer_nif","supplier_cif","open_only","amount_kind","min_amount_eur","max_amount_eur","published_from","published_to","limit","cursor"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","range":"422 validation_failed","combinations":"supplier_cif supports phase, buyer_nif, province and publication dates; supplier_cif plus open_only or amount_kind/min_amount_eur/max_amount_eur returns 422 until a compound projection exists"},
        "parameters": [
          {"name":"q","in":"query","schema":{"type":"string","minLength":3,"maxLength":200},"description":"Object/buyer terms only; supplier column is excluded."},
          {"name":"cpv","in":"query","schema":{"type":"string","pattern":"^[0-9]{2,8}$"},"description":"Indexed PLACSP v1.1 CPV prefix matching primary or lot codes. It may combine only with published_from/published_to; q or another structured filter returns 422. Missing table or exact CPV-date index fails closed with 503; no request-path fallback is executed."},
          {"name":"phase","in":"query","schema":{"type":"string","enum":["PUB","PRE","EV","ADJ","RES","ANUL"]}},
          {"name":"province","in":"query","schema":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"description":"Partial coverage: rows not yet geocoded are excluded."},
          {"name":"buyer_nif","in":"query","schema":{"type":"string","pattern":"^[ABCDEFGHJNPQRSUVW][0-9]{7}[0-9A-J]$"},"description":"Entity identifier only; DNI/NIE is rejected."},
          {"name":"supplier_cif","in":"query","schema":{"type":"string","pattern":"^[ABCDEFGHJNPQRSUVW][0-9]{7}[0-9A-J]$"},"description":"Corporate CIF only; DNI/NIE is rejected. Matches the top-level adjudicatario or any materialized coadjudicator through the generation-bound offline 0062 projection. A summary item may display another supplier; detail retains all materialized results."},
          {"name":"open_only","in":"query","schema":{"type":"boolean","default":false},"description":"Strict boolean. Canonical true/false and compatibility query lexemes 1/0 are accepted; every other value is rejected."},
          {"name":"amount_kind","in":"query","schema":{"type":"string","enum":["budget","estimated","award"]},"description":"Required whenever min_amount_eur or max_amount_eur is used; prevents mixing monetary semantics."},
          {"name":"min_amount_eur","in":"query","schema":{"type":"number","minimum":0,"maximum":10000000000},"description":"Minimum value for the explicit amount_kind; only EUR projections are currently filterable."},
          {"name":"max_amount_eur","in":"query","schema":{"type":"number","minimum":0,"maximum":10000000000},"description":"Maximum value for the explicit amount_kind; only EUR projections are currently filterable."},
          {"name":"published_from","in":"query","schema":{"type":"string","format":"date"},"description":"Real UTC calendar date; impossible dates are rejected."},
          {"name":"published_to","in":"query","schema":{"type":"string","format":"date"},"description":"Real UTC calendar date; impossible dates and a value before published_from are rejected."},
          {"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":25}},
          {"name":"cursor","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{8,256}$"},"description":"Opaque cursor bound to the immutable PLACSP projection generation, current ordering mode and complete normalized filter set; a projection swap or filter change invalidates it. It is not an authentication credential and clients must never synthesize it."}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },"description":"Sanitized notice page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenderSearchResponse"}}}},
          "400": {"$ref":"#/components/responses/BadRequest"},
          "422": {"description":"A validly typed value is outside its documented range, a lower bound exceeds its upper bound, full-text is combined with a structured filter, CPV plus a non-date structured filter requires an offline compound projection, or supplier_cif is combined with open_only or any monetary filter before its compound offline projection exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},
          "429": {"$ref":"#/components/responses/TooManyRequests"},
          "500": {"$ref":"#/components/responses/InternalServerError"},
          "503": {"description":"PLACSP dataset, public FTS, CPV prefix projection or exact CPV-date index unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}
        }
      }
    },
    "/api/v1/tenders/{key}": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "tenders:read",
        "operationId": "getTender",
        "tags": ["Public Procurement"],
        "summary": "Get a sanitized procurement notice",
        "description": "Returns an explicit public projection by stable url_key, including materialized CODICE v3 lots, CPV codes and results when available. Raw XML, local paths, document binaries and uncertain supplier identities are never returned.",
        "x-data-source": "PLACSP",
        "x-query-contract": {"allowed":[],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter"},
        "parameters": [
          {"name":"key","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9]{6,48}$","example":"0d7736fd49044863"}}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },"description":"Sanitized notice detail","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["schema_version","tender","lots","results","collections","coverage","attribution","disclaimer","_source_catalog","_data_sources_used"],"properties":{"schema_version":{"type":"string"},"tender":{"$ref":"#/components/schemas/TenderNotice"},"lots":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/TenderLot"}},"results":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/TenderResult"}},"collections":{"$ref":"#/components/schemas/TenderCollectionMetadata"},"coverage":{
            "$ref": "#/components/schemas/TenderCoverage"
          },"attribution":{"type":"string"},"disclaimer":{"type":"string"},"_source_catalog":{"$ref":"#/components/schemas/SourceCatalogEnvelope"},"_data_sources_used":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/PublicSourcePolicyMetadata"}},"_attributions":{"type":"object","additionalProperties":{"type":"string"}}}}}}},
          "400": {"$ref":"#/components/responses/BadRequest"},
          "404": {"$ref":"#/components/responses/NotFound"},
          "429": {"$ref":"#/components/responses/TooManyRequests"},
          "500": {"$ref":"#/components/responses/InternalServerError"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/tenders/stats": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "tenders:read",
        "operationId": "getTenderStats",
        "tags": ["Public Procurement"],
        "summary": "Get non-personal procurement coverage metrics",
        "description": "Publishes O(1) materialized record, freshness, document, geography and CODICE-v3 coverage. Monetary rollups are deliberately omitted even though amount semantics are separated.",
        "x-data-source": "PLACSP",
        "x-query-contract": {"allowed":[],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter"},
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },"description":"Coverage and quality metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenderStats"}}}},
          "400": {"$ref":"#/components/responses/BadRequest"},
          "429": {"$ref":"#/components/responses/TooManyRequests"},
          "500": {"$ref":"#/components/responses/InternalServerError"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/tenders/suppliers": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "tenders:read",
        "operationId": "listTenderSuppliers",
        "tags": ["Public Procurement"],
        "summary": "List corporate suppliers by award count",
        "description": "Only rows joined to an OpenMercantil company with a matching corporate CIF are eligible. Natural persons are omitted. Ranking is by documented award count; monetary totals are not published.",
        "x-data-source": "PLACSP+BORME",
        "x-query-contract": {"allowed":["limit"],"unknown":"400 invalid_parameter","non_scalar":"400 invalid_parameter","range":"422 validation_failed"},
        "parameters": [
          {"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"}
            },"description":"Sanitized corporate supplier ranking","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenderSupplierResponse"}}}},
          "400": {"$ref":"#/components/responses/BadRequest"},
          "422": {"description":"limit is a valid integer but outside 1..50","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},
          "429": {"$ref":"#/components/responses/TooManyRequests"},
          "500": {"$ref":"#/components/responses/InternalServerError"},
          "503": {"$ref": "#/components/responses/PublicReadUnavailable"}
        }
      }
    },
    "/api/v1/integrations": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "integrations:read",
        "operationId": "listIntegrations",
        "tags": ["Integrations"],
        "summary": "List public integration capabilities",
        "description": "Versioned fail-closed catalog that reports legal egress permission separately from technical transport availability. public_read is false when permission exists but no safe projection is active; separate_authority delegates validation to the endpoint's own fail-closed contract. Sources in review, restricted or unknown are omitted. The query contract is closed: capability is optional, but when present it must match the documented lowercase pattern byte-for-byte; empty, padded or upper-case values and unknown parameters return 400. Provenance contains exactly the sources represented by the returned items. This is not an operator health probe and never includes credentials, OAuth tokens, webhook secrets, billing or internal errors.",
        "parameters": [
          {"name":"capability","in":"query","schema":{"type":"string","pattern":"^[a-z][a-z0-9_-]{1,40}$"}},
          {"$ref": "#/components/parameters/IfNoneMatchHeader"}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "Cache-Control": {"$ref": "#/components/headers/PrivateRevalidationCacheControl"}
            },"description":"Public integration catalog","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationListResponse"}}}},
          "304": {
            "description":"The legal catalog and technical transport snapshot have not changed",
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "Cache-Control": {"$ref": "#/components/headers/PrivateRevalidationCacheControl"}
            }
          },
          "400": {"$ref":"#/components/responses/BadRequest"},
          "429": {"$ref":"#/components/responses/TooManyRequests"},
          "503": {"$ref":"#/components/responses/LegalLayerUnavailable"}
        }
      }
    },
    "/api/v1/integrations/{slug}": {
      "get": {
        "security": [
          {},
          {"apiKey": []},
          {"bearerAuth": []}
        ],
        "x-api-credential-scope": "integrations:read",
        "operationId": "getIntegration",
        "tags": ["Integrations"],
        "summary": "Get one public integration contract",
        "description": "Return the legal-egress decision and the independent technical transport status for one catalogued integration. This detail route accepts no query parameters; unknown parameters return 400.",
        "parameters": [
          {"name":"slug","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"}},
          {"$ref": "#/components/parameters/IfNoneMatchHeader"}
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "Cache-Control": {"$ref": "#/components/headers/PrivateRevalidationCacheControl"}
            },"description":"Public integration metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationDetailResponse"}}}},
          "304": {
            "description":"The legal decision and technical transport snapshot have not changed",
            "headers": {
              "X-Data-Sources": {"$ref": "#/components/headers/XDataSources"},
              "X-Source-Catalog-Version": {"$ref": "#/components/headers/XSourceCatalogVersion"},
              "X-Attribution-Required": {"$ref": "#/components/headers/XAttributionRequired"},
              "ETag": {"$ref": "#/components/headers/EntityTag"},
              "Cache-Control": {"$ref": "#/components/headers/PrivateRevalidationCacheControl"}
            }
          },
          "400": {"$ref":"#/components/responses/BadRequest"},
          "404": {"$ref":"#/components/responses/NotFound"},
          "429": {"$ref":"#/components/responses/TooManyRequests"},
          "503": {"$ref":"#/components/responses/LegalLayerUnavailable"}
        }
      }
    }
  },
  "components": {
    "schemas": {
      "UserPersonaUpdateRequest": {
        "type": "object",
        "required": ["persona"],
        "properties": {
          "persona": {"type": "string", "minLength": 1, "maxLength": 80, "description": "Slug returned by GET /api/v1/user/persona."}
        },
        "additionalProperties": false
      },
      "UserSegmentFilters": {
        "type": "object",
        "minProperties": 1,
        "description": "Corporate-only filters executed exclusively over the immutable company_public_v2 sidecar. At least one effective anchor is required: provincia, cnae_prefix, a capital bound, a year bound or recent_days. `forma` and `estado` are deliberately not accepted; stored legacy filters containing either fail closed. Without provincia/cnae_prefix, capital and temporal anchors cannot be combined; capital-only anchors accept only capital_desc/capital_asc (or the default), and temporal-only anchors accept only recent/oldest (or the default).",
        "x-effective-filter-fields": ["provincia", "cnae_prefix", "capital_min", "capital_max", "year_min", "year_max", "recent_days"],
        "x-rejected-fields": {
          "forma": "legal_form_filter_unavailable",
          "estado": "status_filter_unavailable"
        },
        "x-rejected-combinations": [
          {
            "when": "capital bound plus temporal bound without provincia or cnae_prefix",
            "error": "unsupported_filter_combination",
            "status": 422
          },
          {
            "when": "capital-only anchor with sort other than capital_desc or capital_asc",
            "error": "unsupported_sort_for_anchor",
            "status": 422
          },
          {
            "when": "temporal-only anchor with sort other than recent or oldest",
            "error": "unsupported_sort_for_anchor",
            "status": 422
          }
        ],
        "properties": {
          "provincia": {"type": "string", "minLength": 1, "maxLength": 80, "description": "Canonical Spanish province name or supported alias; matched exactly after normalization."},
          "cnae_prefix": {"type": "string", "pattern": "^[0-9]{1,4}$"},
          "capital_min": {"type": "integer", "minimum": 0, "maximum": 90000000000000, "description": "Euros. Must not exceed capital_max when both are present."},
          "capital_max": {"type": "integer", "minimum": 0, "maximum": 90000000000000, "description": "Euros. Must be greater than or equal to capital_min when both are present."},
          "year_min": {"type": "integer", "minimum": 1800, "maximum": 2200, "description": "Inclusive year of the first documentary record; must not exceed year_max."},
          "year_max": {"type": "integer", "minimum": 1800, "maximum": 2200, "description": "Inclusive year of the first documentary record; must be greater than or equal to year_min."},
          "recent_days": {"type": "integer", "minimum": 1, "maximum": 3650, "description": "First documentary record within this rolling number of days."},
          "sort": {"type": "string", "enum": ["capital_desc", "capital_asc", "acts_desc", "oldest", "recent"], "description": "Indexed ordering. The accepted value depends on the effective anchor as documented in x-rejected-combinations."}
        },
        "additionalProperties": false
      },
      "UserSegmentStoredFilters": {
        "type": "object",
        "description": "Read-only decoded filters_json from an existing segment. New writes must use UserSegmentFilters. Historic records may still contain removed keys such as forma or estado; clients must present them as unavailable and execution fails closed rather than ignoring them.",
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "UserSegmentCreateRequest": {
        "type": "object",
        "required": ["name", "filters"],
        "properties": {
          "name": {"type": "string", "minLength": 1, "maxLength": 120},
          "description": {"type": "string", "maxLength": 5000},
          "filters": {"$ref": "#/components/schemas/UserSegmentFilters"},
          "persona": {"type": ["string", "null"], "maxLength": 80},
          "icon": {"type": ["string", "null"], "maxLength": 80},
          "pinned": {"type": "boolean", "default": false}
        },
        "additionalProperties": false
      },
      "UserSegmentUpdateRequest": {
        "type": "object",
        "minProperties": 1,
        "properties": {
          "name": {"type": "string", "minLength": 1, "maxLength": 120},
          "description": {"type": "string", "maxLength": 5000},
          "filters_json": {"$ref": "#/components/schemas/UserSegmentFilters"},
          "icon": {"type": ["string", "null"], "maxLength": 80},
          "pinned": {"type": "boolean"}
        },
        "additionalProperties": false
      },
      "UserListCreateRequest": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": {"type": "string", "minLength": 1, "maxLength": 120},
          "description": {"type": "string", "maxLength": 5000},
          "color": {"type": ["string", "null"], "pattern": "^#[0-9A-Fa-f]{6}$"},
          "kind": {"type": "string", "enum": ["company", "person", "mixed"], "default": "company"}
        },
        "additionalProperties": false
      },
      "UserListUpdateRequest": {
        "type": "object",
        "minProperties": 1,
        "properties": {
          "name": {"type": "string", "minLength": 1, "maxLength": 120},
          "description": {"type": "string", "maxLength": 5000},
          "color": {"type": ["string", "null"], "pattern": "^#[0-9A-Fa-f]{6}$"},
          "kind": {"type": "string", "enum": ["company", "person", "mixed"]}
        },
        "additionalProperties": false
      },
      "UserListItemCreateRequest": {
        "type": "object",
        "required": ["type", "slug"],
        "properties": {
          "type": {"type": "string", "enum": ["company", "person"]},
          "slug": {"type": "string", "minLength": 1, "maxLength": 255},
          "note": {"type": "string", "maxLength": 5000}
        },
        "additionalProperties": false
      },
      "UserNoteCreateRequest": {
        "type": "object",
        "required": ["target_type", "target_id", "body"],
        "properties": {
          "target_type": {"type": "string", "enum": ["company", "person", "sector", "borme_id", "free"]},
          "target_id": {"type": "string", "minLength": 1, "maxLength": 255},
          "title": {"type": "string", "maxLength": 255},
          "body": {"type": "string", "minLength": 1, "maxLength": 50000},
          "pinned": {"type": "boolean", "default": false}
        },
        "additionalProperties": false
      },
      "UserNoteUpdateRequest": {
        "type": "object",
        "minProperties": 1,
        "properties": {
          "title": {"type": "string", "maxLength": 255},
          "body": {"type": "string", "minLength": 1, "maxLength": 50000},
          "pinned": {"type": "boolean"}
        },
        "additionalProperties": false
      },
      "UserTagCreateRequest": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": {"type": "string", "minLength": 1, "maxLength": 60},
          "color": {"type": ["string", "null"], "pattern": "^#[0-9A-Fa-f]{6}$"}
        },
        "additionalProperties": false
      },
      "UserTagAssignmentRequest": {
        "type": "object",
        "required": ["target_type", "target_id"],
        "properties": {
          "target_type": {"type": "string", "enum": ["company", "person", "sector", "borme_id"]},
          "target_id": {"type": "string", "minLength": 1, "maxLength": 255}
        },
        "additionalProperties": false
      },
      "UserOrganizationNameRequest": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": {"type": "string", "minLength": 2, "maxLength": 80}
        },
        "additionalProperties": false
      },
      "UserOrganizationInviteRequest": {
        "type": "object",
        "required": ["email"],
        "properties": {
          "email": {"type": "string", "format": "email", "maxLength": 320},
          "role": {"type": "string", "enum": ["admin", "member"], "default": "member"}
        },
        "additionalProperties": false
      },
      "UserOrganizationMemberRoleRequest": {
        "type": "object",
        "required": ["role"],
        "properties": {
          "role": {"type": "string", "enum": ["admin", "member"]}
        },
        "additionalProperties": false
      },
      "KycPersonLookupRequest": {
        "type": "object",
        "required": ["dni_or_nie", "finalidad"],
        "properties": {
          "dni_or_nie": {"type": "string", "minLength": 8, "maxLength": 12, "writeOnly": true, "x-sensitive": true, "description": "DNI/NIE supplied for this authenticated KYC request; never use it in public company/person routes."},
          "finalidad": {"type": "string", "minLength": 12, "maxLength": 200, "description": "Declared legitimate purpose recorded in the account audit log."}
        },
        "additionalProperties": false
      },
      "ApiCredential": {
        "type": "object",
        "required": ["id", "name", "prefix", "last4", "hint", "scopes", "status", "created_at"],
        "properties": {
          "id": {"type": "integer", "minimum": 1},
          "name": {"type": "string", "maxLength": 80},
          "prefix": {"type": "string", "description": "Non-secret identification prefix."},
          "last4": {"type": "string", "minLength": 4, "maxLength": 4},
          "hint": {"type": "string"},
          "scopes": {"type": "array", "items": {"type": "string", "enum": ["public:read", "companies:read", "people:read", "tenders:read", "legal:read", "integrations:read", "exports:read", "account:read"]}, "uniqueItems": true},
          "status": {"type": "string", "enum": ["active", "expired", "revoked"]},
          "created_at": {"type": "string", "format": "date-time"},
          "expires_at": {"type": ["string", "null"], "format": "date-time"},
          "revoked_at": {"type": ["string", "null"], "format": "date-time"},
          "last_used_at": {"type": ["string", "null"], "format": "date-time"},
          "rotated_from_id": {"type": ["integer", "null"]},
          "legacy_migrated": {"type": "boolean"}
        },
        "additionalProperties": false
      },
      "ApiCredentialCreateRequest": {
        "type": "object",
        "required": ["scopes"],
        "properties": {
          "name": {"type": "string", "minLength": 1, "maxLength": 80},
          "scopes": {"type": "array", "items": {"type": "string", "enum": ["public:read", "companies:read", "people:read", "tenders:read", "legal:read", "integrations:read", "exports:read", "account:read"]}, "uniqueItems": true},
          "expires_at": {"type": ["string", "null"], "format": "date-time", "description": "Default 90 days; maximum 366 days."}
        },
        "additionalProperties": false
      },
      "ApiCredentialRotateRequest": {
        "type": "object",
        "properties": {
          "name": {"type": "string", "minLength": 1, "maxLength": 80},
          "scopes": {"type": "array", "items": {"type": "string", "enum": ["public:read", "companies:read", "people:read", "tenders:read", "legal:read", "integrations:read", "exports:read", "account:read"]}, "uniqueItems": true, "minItems": 1},
          "expires_at": {"type": ["string", "null"], "format": "date-time", "description": "Omitted preserves the current expiry; null resets to the standard 90-day expiry; maximum 366 days."}
        },
        "additionalProperties": false
      },
      "ApiCredentialOneTimeResponse": {
        "type": "object",
        "required": ["ok", "credential", "token", "token_visible_once", "idempotency_replayed", "idempotency_expires_at"],
        "properties": {
          "ok": {"type": "boolean", "const": true},
          "credential": {"$ref": "#/components/schemas/ApiCredential"},
          "token": {"type": "string", "pattern": "^omk_live_[A-Za-z0-9_-]{43}$", "readOnly": true, "x-sensitive": true, "x-visible-once": true, "description": "Visible only in the original create/rotate response and identical Idempotency-Key replays during the 24-hour recovery window; never recoverable through list/get."},
          "token_visible_once": {"type": "boolean", "const": true},
          "replaced_credential_id": {"type": "integer"},
          "idempotency_replayed": {"type": "boolean", "readOnly": true},
          "idempotency_expires_at": {"type": "integer", "minimum": 1, "readOnly": true, "description": "Unix timestamp for the encrypted replay window."}
        },
        "additionalProperties": false
      },
      "OutboundWebhookEventTypeV1": {
        "type": "string",
        "description": "Exact subscription allowlist for webhook payload contract 1.0. Unknown event types, wildcard subscriptions and unsupported schema versions fail closed. Adding an event requires an explicit runtime, OpenAPI and contract-test change so existing subscriptions never gain future events implicitly.",
        "enum": [
          "alert.triggered",
          "tender.matched",
          "tender.deadline"
        ],
        "x-webhook-event-contract-version": "1.0",
        "x-fail-closed": true
      },
      "OutboundWebhookEventSubscriptionsV1": {
        "type": "array",
        "description": "Events with a currently wired durable producer. Contracted-but-unwired event types are not subscribable. An empty input is normalized to alert.triggered; wildcard, inactive and unknown values are rejected.",
        "items": {"$ref": "#/components/schemas/OutboundWebhookEventTypeV1"},
        "maxItems": 3,
        "uniqueItems": true,
        "x-webhook-event-contract-version": "1.0"
      },
      "OutboundWebhookEventCatalogV1": {
        "description": "Exact account-visible list of events with a currently wired durable producer.",
        "allOf": [
          {"$ref": "#/components/schemas/OutboundWebhookEventSubscriptionsV1"},
          {"type": "array", "minItems": 3, "maxItems": 3}
        ],
        "x-webhook-event-contract-version": "1.0"
      },
      "OutboundWebhookContractedEventTypeV1": {
        "type": "string",
        "description": "Versioned event names with a defined payload contract. Only names also present in OutboundWebhookEventTypeV1 are currently subscribable.",
        "enum": [
          "alert.triggered",
          "borme.daily",
          "cartera.change",
          "sanction.matched",
          "segment.executed",
          "tender.matched",
          "tender.deadline",
          "webhook.test"
        ],
        "x-webhook-event-contract-version": "1.0"
      },
      "OutboundWebhookContractedEventCatalogV1": {
        "type": "array",
        "description": "All event payload contracts known by this API version, including contracted-but-unwired events that cannot yet be subscribed.",
        "items": {"$ref": "#/components/schemas/OutboundWebhookContractedEventTypeV1"},
        "minItems": 8,
        "maxItems": 8,
        "uniqueItems": true,
        "x-webhook-event-contract-version": "1.0"
      },
      "OutboundWebhook": {
        "type": "object",
        "required": ["id", "url", "events", "active", "secret_prefix", "created_at"],
        "properties": {
          "id": {"type": "integer", "minimum": 1},
          "url": {"type": "string", "format": "uri", "pattern": "^https://"},
          "events": {"$ref": "#/components/schemas/OutboundWebhookEventSubscriptionsV1"},
          "active": {"type": "boolean"},
          "secret_prefix": {"type": "string", "maxLength": 12, "description": "Non-secret identification prefix."},
          "key_id": {"type": ["string", "null"], "description": "Public identifier of the current HMAC signing key."},
          "secret_storage": {"type": "string", "enum": ["encrypted", "migration_required"]},
          "last_success_at": {"type": ["string", "null"], "format": "date-time"},
          "created_at": {"type": "string", "format": "date-time"}
        },
        "additionalProperties": false
      },
      "OutboundWebhookCreateRequest": {
        "type": "object",
        "required": ["url", "events"],
        "properties": {
          "url": {"type": "string", "format": "uri", "pattern": "^https://"},
          "events": {"$ref": "#/components/schemas/OutboundWebhookEventSubscriptionsV1"}
        },
        "additionalProperties": false
      },
      "OutboundWebhookUpdateRequest": {
        "type": "object",
        "minProperties": 1,
        "properties": {
          "url": {"type": "string", "format": "uri", "pattern": "^https://"},
          "events": {"$ref": "#/components/schemas/OutboundWebhookEventSubscriptionsV1"},
          "active": {"type": "boolean"}
        },
        "additionalProperties": false
      },
      "OutboundWebhookOneTimeResponse": {
        "type": "object",
        "required": ["ok", "webhook", "secret_visible_once", "idempotency_replayed", "idempotency_expires_at"],
        "properties": {
          "ok": {"type": "boolean", "const": true},
          "webhook": {
            "type": "object",
            "required": ["id", "secret", "key_id"],
            "properties": {
              "id": {"type": "integer", "minimum": 1},
              "secret": {"type": "string", "pattern": "^[a-f0-9]{64}$", "readOnly": true, "x-sensitive": true, "x-visible-once": true, "description": "Visible only in the original mutation response and identical Idempotency-Key replays during the 24-hour recovery window; never returned by list/get."},
              "key_id": {"type": "string"},
              "events": {"$ref": "#/components/schemas/OutboundWebhookEventSubscriptionsV1"}
            },
            "additionalProperties": false
          },
          "secret_visible_once": {"type": "boolean", "const": true},
          "idempotency_replayed": {"type": "boolean", "readOnly": true},
          "idempotency_expires_at": {"type": "integer", "minimum": 1, "readOnly": true, "description": "Unix timestamp for the encrypted replay window."}
        },
        "additionalProperties": false
      },
      "WebhookWorkerHealth": {
        "type": "object",
        "required": ["available", "status", "reason"],
        "properties": {
          "available": {"type": "boolean"},
          "status": {"type": "string"},
          "age_seconds": {"type": ["integer", "null"]},
          "reason": {"type": "string"}
        },
        "additionalProperties": false
      },
      "PublicSourcePolicyMetadata": {
        "type": "object",
        "additionalProperties": false,
        "required": ["slug", "name", "license", "attribution_required", "reuse_conditions", "policy_effective_date", "reviewed_at", "catalog_version"],
        "properties": {
          "slug": {"type": "string"},
          "name": {"type": "string"},
          "license": {"type": "string"},
          "license_url": {"type": ["string", "null"], "format": "uri"},
          "attribution_required": {"type": "boolean"},
          "attribution_text": {"type": ["string", "null"]},
          "official_url": {"type": ["string", "null"], "format": "uri"},
          "reuse_conditions": {"type": "string", "description": "Condiciones de reutilizacion que el consumidor debe conservar al presentar o transformar el dato."},
          "policy_effective_date": {"type": "string", "format": "date"},
          "reviewed_at": {"type": "string", "format": "date"},
          "data_updated_at": {"type": ["string", "null"], "format": "date-time"},
          "catalog_version": {"type": "string"}
        }
      },
      "PublicCompanyDownload": {
        "type": "object",
        "additionalProperties": false,
        "required": ["filename", "download_url", "media_type", "bytes", "row_count", "sha256", "source_generation"],
        "properties": {
          "filename": {
            "type": "string",
            "enum": ["muestra_empresas_100.csv", "muestra_nuevas_50.json", "company_top.json"]
          },
          "download_url": {
            "type": "string",
            "enum": ["/assets/samples/muestra_empresas_100.csv", "/assets/samples/muestra_nuevas_50.json", "/descargas/company_top.json"]
          },
          "media_type": {"type": "string", "enum": ["text/csv", "application/json"]},
          "bytes": {"type": "integer", "minimum": 1},
          "row_count": {"type": "integer", "minimum": 0},
          "sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
          "source_generation": {"type": "string", "pattern": "^cpv2-[a-f0-9]{64}$"}
        }
      },
      "PublicCompanyDownloadCatalog": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schema_version",
          "projection",
          "artifact_contract_version",
          "source_generation",
          "company_count",
          "acts_count_sum",
          "min_first_seen",
          "max_last_seen",
          "count",
          "items",
          "source_metadata",
          "_legal_notice",
          "_source_catalog",
          "_data_sources_used",
          "_attributions"
        ],
        "properties": {
          "schema_version": {"type": "string", "const": "1.0"},
          "projection": {"type": "string", "const": "company_public_download_catalog_v1"},
          "artifact_contract_version": {"type": "string", "const": "1.1"},
          "source_generation": {"type": "string", "pattern": "^cpv2-[a-f0-9]{64}$"},
          "company_count": {"type": "integer", "minimum": 0},
          "acts_count_sum": {"type": "integer", "minimum": 0},
          "min_first_seen": {"type": "string", "format": "date"},
          "max_last_seen": {"type": "string", "format": "date"},
          "count": {"type": "integer", "const": 3},
          "items": {
            "type": "array",
            "minItems": 3,
            "maxItems": 3,
            "items": {"$ref": "#/components/schemas/PublicCompanyDownload"}
          },
          "source_metadata": {"$ref": "#/components/schemas/PublicSourcePolicyMetadata"},
          "_legal_notice": {"type": "string", "minLength": 1},
          "_source_catalog": {"$ref": "#/components/schemas/SourceCatalogEnvelope"},
          "_data_sources_used": {
            "type": "array",
            "minItems": 1,
            "items": {"$ref": "#/components/schemas/PublicSourcePolicyMetadata"}
          },
          "_attributions": {
            "type": "object",
            "required": ["borme"],
            "properties": {"borme": {"type": "string", "minLength": 1}},
            "additionalProperties": false
          }
        }
      },
      "PublicSourceMetadata": {
        "type": "object",
        "additionalProperties": false,
        "required": ["slug", "name", "license", "attribution_required", "reuse_conditions", "policy_effective_date", "catalog_version", "freshness"],
        "properties": {
          "slug": {"type": "string"},
          "name": {"type": "string"},
          "license": {"type": "string"},
          "license_url": {"type": ["string", "null"], "format": "uri"},
          "attribution_required": {"type": "boolean"},
          "attribution_text": {"type": ["string", "null"]},
          "official_url": {"type": ["string", "null"], "format": "uri"},
          "reuse_conditions": {"type": "string", "description": "Condiciones de reutilizacion que el consumidor debe conservar al presentar o transformar el dato."},
          "policy_effective_date": {"type": "string", "format": "date"},
          "reviewed_at": {"type": ["string", "null"], "format": "date"},
          "data_updated_at": {"type": ["string", "null"], "format": "date-time"},
          "catalog_version": {"type": "string"},
          "freshness": {"type": "string", "enum": ["current", "stale", "unknown"]}
        }
      },
      "PublicSourceStatusResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["generated_at", "source_catalog_version", "count", "sources", "_legal_notice"],
        "properties": {
          "generated_at": {"type": "string", "format": "date-time"},
          "source_catalog_version": {"type": "string"},
          "count": {"type": "integer", "minimum": 0},
          "sources": {"type": "array", "items": {"$ref": "#/components/schemas/PublicSourceMetadata"}},
          "_legal_notice": {"type": "string"}
        }
      },
      "TenderParty": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "name": {"type": ["string", "null"]},
          "cif": {"type": ["string", "null"], "description": "Corporate CIF only."},
          "nif": {"type": ["string", "null"], "description": "Public-body NIF; never a supplier DNI/NIE."},
          "dir3": {"type": ["string", "null"]},
          "company_slug": {"type": ["string", "null"]},
          "withheld": {"type": "boolean"}
        }
      },
      "TenderMoney": {
        "type": "object",
        "additionalProperties": false,
        "required": ["value", "currency"],
        "properties": {
          "value": {"type": ["number", "null"], "minimum": 0, "maximum": 10000000000},
          "currency": {"type": ["string", "null"], "pattern": "^[A-Z]{3}$"}
        }
      },
      "TenderNotice": {
        "type": "object",
        "additionalProperties": false,
        "required": ["key", "folder_id", "object", "buyer", "supplier", "supplier_withheld", "cpv", "cpv_codes", "contract_type", "procedure", "amounts", "reported_amount_eur", "reported_tax_exclusive_amount_eur", "amount_quality", "amount_semantics", "phase", "phase_description", "published_at", "awarded_at", "formalised_at", "submission_deadline", "is_open", "province", "province_slug", "document_count", "lot_count", "result_count", "supplier_count", "official_url", "parser_version", "source"],
        "properties": {
          "key": {"type": "string", "pattern": "^[a-z0-9]{6,48}$"},
          "folder_id": {"type": ["string", "null"]},
          "object": {"type": "string"},
          "buyer": {"$ref": "#/components/schemas/TenderParty"},
          "supplier": {
            "oneOf": [
              {"$ref": "#/components/schemas/TenderParty"},
              {"type": "null"}
            ]
          },
          "supplier_withheld": {"type": "boolean"},
          "cpv": {"type": ["string", "null"]},
          "cpv_codes": {"type": "array", "items": {"type": "string", "pattern": "^[0-9]{2,8}$"}, "uniqueItems": true},
          "contract_type": {"type": ["string", "null"], "description": "Raw CODICE code when no verified codelist label is available."},
          "procedure": {"type": ["string", "null"], "description": "Raw CODICE code when no verified codelist label is available."},
          "amounts": {
            "type": "object",
            "additionalProperties": false,
            "required": ["budget_total", "budget_tax_exclusive", "estimated_total", "award_payable_total"],
            "properties": {
              "budget_total": {"$ref": "#/components/schemas/TenderMoney"},
              "budget_tax_exclusive": {"$ref": "#/components/schemas/TenderMoney"},
              "estimated_total": {"$ref": "#/components/schemas/TenderMoney"},
              "award_payable_total": {"$ref": "#/components/schemas/TenderMoney"}
            }
          },
          "reported_amount_eur": {"type": ["number", "null"], "deprecated": true, "description": "Compatibility field: award_payable_total only when its currency is EUR. Not proof of payment/executed spend."},
          "reported_tax_exclusive_amount_eur": {"type": ["number", "null"], "deprecated": true},
          "amount_quality": {"type": "string", "description": "Projection quality marker such as complete, separated_reported, missing, legacy_withheld or outlier_withheld."},
          "amount_semantics": {"type": "string"},
          "phase": {"type": ["string", "null"], "enum": ["PUB", "PRE", "EV", "ADJ", "RES", "ANUL", null]},
          "phase_description": {"type": ["string", "null"]},
          "published_at": {"type": ["string", "null"], "format": "date"},
          "awarded_at": {"type": ["string", "null"], "format": "date"},
          "formalised_at": {"type": ["string", "null"], "format": "date"},
          "submission_deadline": {"type": ["string", "null"], "format": "date"},
          "is_open": {"type": "boolean"},
          "province": {"type": ["string", "null"]},
          "province_slug": {"type": ["string", "null"]},
          "document_count": {"type": "integer", "minimum": 0},
          "lot_count": {"type": "integer", "minimum": 0},
          "result_count": {"type": "integer", "minimum": 0},
          "supplier_count": {"type": "integer", "minimum": 0},
          "official_url": {"type": ["string", "null"], "format": "uri"},
          "parser_version": {"type": ["string", "null"]},
          "source": {"type": "string", "const": "PLACSP"}
        }
      },
      "TenderLot": {
        "type": "object",
        "additionalProperties": false,
        "required": ["lot_id", "object", "budget_total", "budget_tax_exclusive", "estimated_total", "nuts_code", "cpv_codes"],
        "properties": {
          "lot_id": {"type": "string"},
          "object": {"type": ["string", "null"]},
          "budget_total": {"$ref": "#/components/schemas/TenderMoney"},
          "budget_tax_exclusive": {"$ref": "#/components/schemas/TenderMoney"},
          "estimated_total": {"$ref": "#/components/schemas/TenderMoney"},
          "nuts_code": {"type": ["string", "null"]},
          "cpv_codes": {"type": "array", "items": {"type": "string", "pattern": "^[0-9]{2,8}$"}}
        }
      },
      "TenderResultSupplier": {
        "type": "object",
        "additionalProperties": false,
        "required": ["supplier", "supplier_withheld"],
        "properties": {
          "supplier": {"oneOf": [{"$ref": "#/components/schemas/TenderParty"}, {"type": "null"}]},
          "supplier_withheld": {"type": "boolean"}
        }
      },
      "TenderResult": {
        "type": "object",
        "additionalProperties": false,
        "required": ["lot_id", "result_index", "result_code", "description", "award_date", "formalized_date", "amounts", "amount_quality", "received_tender_quantity", "sme_awarded", "suppliers"],
        "properties": {
          "lot_id": {"type": "string"},
          "result_index": {"type": "integer", "minimum": 0},
          "result_code": {"type": ["string", "null"]},
          "description": {"type": ["string", "null"]},
          "award_date": {"type": ["string", "null"], "format": "date"},
          "formalized_date": {"type": ["string", "null"], "format": "date"},
          "amounts": {
            "type": "object",
            "additionalProperties": false,
            "required": ["award_tax_exclusive", "award_payable", "lower_tender", "higher_tender"],
            "properties": {
              "award_tax_exclusive": {"$ref": "#/components/schemas/TenderMoney"},
              "award_payable": {"$ref": "#/components/schemas/TenderMoney"},
              "lower_tender": {"$ref": "#/components/schemas/TenderMoney"},
              "higher_tender": {"$ref": "#/components/schemas/TenderMoney"}
            }
          },
          "amount_quality": {"type": "string"},
          "received_tender_quantity": {"type": ["integer", "null"], "minimum": 0},
          "sme_awarded": {"type": ["boolean", "null"]},
          "suppliers": {"type": "array", "items": {"$ref": "#/components/schemas/TenderResultSupplier"}}
        }
      },
      "TenderSearchResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["schema_version", "count", "items", "page", "ordering", "filters", "coverage", "attribution", "disclaimer", "_source_catalog", "_data_sources_used"],
        "properties": {
          "schema_version": {"type": "string"},
          "count": {"type": "integer"},
          "items": {"type": "array", "items": {"$ref": "#/components/schemas/TenderNotice"}},
          "page": {
            "type": "object",
            "additionalProperties": false,
            "required": ["limit", "has_more", "next_cursor"],
            "properties": {
              "limit": {"type": "integer"},
              "has_more": {"type": "boolean"},
              "next_cursor": {"type": ["string", "null"]}
            }
          },
          "ordering": {"type": "string", "enum": ["published_desc", "ingestion_desc", "cpv_prefix_published_desc", "deadline_asc", "budget_amount_desc", "estimated_amount_desc", "award_amount_desc"]},
          "filters": {
            "$ref": "#/components/schemas/TenderSearchFilters"
          },
          "coverage": {
            "$ref": "#/components/schemas/TenderCoverage"
          },
          "attribution": {"type": "string"},
          "disclaimer": {"type": "string"},
          "_source_catalog": {"$ref": "#/components/schemas/SourceCatalogEnvelope"},
          "_data_sources_used": {"type": "array", "minItems": 1, "items": {"$ref": "#/components/schemas/PublicSourcePolicyMetadata"}},
          "_attributions": {"type": "object", "additionalProperties": {"type": "string"}}
        }
      },
      "TenderStats": {
        "type": "object",
        "additionalProperties": false,
        "required": ["schema_version", "total_records", "open_records", "records_with_documents", "latest_publication_date", "geography", "data_quality", "projection", "attribution", "_source_catalog", "_data_sources_used"],
        "properties": {
          "schema_version": {"type": "string"},
          "total_records": {"type": "integer"},
          "open_records": {"type": "integer"},
          "records_with_documents": {"type": "integer"},
          "latest_publication_date": {"type": ["string", "null"], "format": "date"},
          "geography": {
            "$ref": "#/components/schemas/TenderGeography"
          },
          "data_quality": {
            "$ref": "#/components/schemas/TenderDataQuality"
          },
          "projection": {
            "type": "object",
            "additionalProperties": false,
            "required": ["schema_version", "generation", "projected_at"],
            "properties": {
              "schema_version": {"type": "string", "const": "1.2"},
              "generation": {"type": "string", "pattern": "^placsp12-[a-f0-9]{64}$"},
              "projected_at": {"type": "string", "format": "date-time"}
            }
          },
          "attribution": {"type": "string"},
          "_source_catalog": {"$ref": "#/components/schemas/SourceCatalogEnvelope"},
          "_data_sources_used": {"type": "array", "minItems": 1, "items": {"$ref": "#/components/schemas/PublicSourcePolicyMetadata"}},
          "_attributions": {"type": "object", "additionalProperties": {"type": "string"}}
        }
      },
      "AggregateProcurementFields": {
        "type": "object",
        "required": [
          "award_procedures_count", "award_procedures_count_status",
          "contracts_count", "contracts_count_status",
          "contracts_total_eur", "contracts_total_eur_status"
        ],
        "properties": {
          "award_procedures_count": {
            "type": "integer", "minimum": 0,
            "description": "Sum of PLACSP award-procedure counts for corporate suppliers in the public v3 projection. It is not a unique-contract count."
          },
          "award_procedures_count_status": {
            "type": "string", "enum": ["public_projection_v3", "projection_unavailable"]
          },
          "contracts_count": {
            "type": "integer", "minimum": 0, "deprecated": true,
            "description": "Compatibility alias of award_procedures_count; consume the canonical field and status instead."
          },
          "contracts_count_status": {
            "type": "string", "const": "award_procedures_per_corporate_supplier_not_unique_contracts"
          },
          "contracts_total_eur": {
            "type": "null", "const": null,
            "description": "Always withheld: no rollup mixes budget, estimate and award concepts."
          },
          "contracts_total_eur_status": {
            "type": "string", "const": "withheld_no_typed_rollup"
          }
        }
      },
      "CcaaStatsRow": {
        "allOf": [
          {"$ref": "#/components/schemas/AggregateProcurementFields"},
          {
            "type": "object",
            "required": ["name", "total", "active", "extinct", "concurso", "total_capital_eur", "provinces"],
            "properties": {
              "name": {"type": "string"},
              "total": {"type": "integer", "minimum": 0},
              "active": {"type": "integer", "minimum": 0},
              "extinct": {"type": "integer", "minimum": 0},
              "concurso": {"type": "integer", "minimum": 0},
              "total_capital_eur": {"type": "integer", "minimum": 0},
              "provinces": {"type": "array", "items": {"type": "string"}}
            }
          }
        ]
      },
      "CcaaStatsResponse": {
        "type": "object",
        "required": ["count", "ccaa", "source", "updated"],
        "properties": {
          "count": {"type": "integer", "minimum": 0},
          "ccaa": {"type": "array", "items": {"$ref": "#/components/schemas/CcaaStatsRow"}},
          "source": {"type": "string"},
          "updated": {"type": ["string", "null"], "format": "date-time", "description": "Offline projection generation time; null when legacy cache provenance is unavailable."}
        }
      },
      "SectorStatsRow": {
        "allOf": [
          {"$ref": "#/components/schemas/AggregateProcurementFields"},
          {
            "type": "object",
            "required": ["section", "name", "total", "active", "extinct", "concurso", "total_capital_eur"],
            "properties": {
              "section": {"type": "string", "pattern": "^[A-U]$"},
              "name": {"type": "string"},
              "total": {"type": "integer", "minimum": 0},
              "active": {"type": "integer", "minimum": 0},
              "extinct": {"type": "integer", "minimum": 0},
              "concurso": {"type": "integer", "minimum": 0},
              "total_capital_eur": {"type": "integer", "minimum": 0}
            }
          }
        ]
      },
      "SectorStatsResponse": {
        "type": "object",
        "required": ["count", "sections", "source", "updated"],
        "properties": {
          "count": {"type": "integer", "minimum": 0},
          "sections": {"type": "array", "items": {"$ref": "#/components/schemas/SectorStatsRow"}},
          "source": {"type": "string"},
          "updated": {"type": ["string", "null"], "format": "date-time", "description": "Offline projection generation time; null when legacy cache provenance is unavailable."}
        }
      },
      "TenderSupplierResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["schema_version", "count", "ranking", "items", "eligibility", "data_quality", "attribution", "_source_catalog", "_data_sources_used"],
        "properties": {
          "schema_version": {"type": "string"},
          "count": {"type": "integer"},
          "ranking": {"type": "string", "enum": ["award_procedures_count_desc", "awards_count_desc"]},
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": ["company_slug", "name", "cif", "notices_count", "award_procedures_count", "tenders_count", "tenders_count_status", "awards_count", "awards_count_status", "buyers_count", "first_date", "last_date", "top_cpv"],
              "properties": {
                "company_slug": {"type": "string"},
                "name": {"type": "string"},
                "cif": {"type": "string"},
                "notices_count": {"type": "integer", "minimum": 0},
                "award_procedures_count": {"type": "integer", "minimum": 0},
                "tenders_count": {"type": "integer"},
                "tenders_count_status": {"type": "string", "const": "deprecated_alias_of_notices_count"},
                "awards_count": {"type": "integer"},
                "awards_count_status": {"type": "string", "const": "deprecated_alias_of_award_procedures_count"},
                "buyers_count": {"type": "integer"},
                "first_date": {"type": ["string", "null"], "format": "date"},
                "last_date": {"type": ["string", "null"], "format": "date"},
                "top_cpv": {"type": ["string", "null"]}
              }
            }
          },
          "eligibility": {"type": "string"},
          "data_quality": {"type": "string"},
          "attribution": {"type": "string"},
          "_source_catalog": {"$ref": "#/components/schemas/SourceCatalogEnvelope"},
          "_data_sources_used": {"type": "array", "minItems": 1, "items": {"$ref": "#/components/schemas/PublicSourcePolicyMetadata"}},
          "_attributions": {"type": "object", "additionalProperties": {"type": "string"}}
        }
      },
      "PublicIntegrationEgressPolicy": {
        "type": "object",
        "description": "Legal permission from the active source catalog. It does not claim that a technical projection is deployed.",
        "required": ["status", "catalog_version", "policy_effective_date", "reviewed_at"],
        "properties": {
          "status": {"type": "string", "const": "allowed"},
          "catalog_version": {"type": "string", "minLength": 1},
          "policy_effective_date": {"type": "string", "format": "date"},
          "reviewed_at": {"type": "string", "format": "date"}
        },
        "additionalProperties": false
      },
      "PublicIntegrationTransport": {
        "type": "object",
        "description": "Technical read-plane status. unavailable has no endpoint; separate_authority delegates fail-closed validation to the listed endpoint contract and is not a health probe.",
        "required": ["status", "projection", "generation", "endpoints"],
        "properties": {
          "status": {"type": "string", "enum": ["available", "unavailable", "separate_authority"]},
          "projection": {"type": ["string", "null"]},
          "generation": {"type": ["string", "null"]},
          "endpoints": {
            "type": "array",
            "maxItems": 8,
            "items": {"type": "string", "pattern": "^/api/v1/"}
          }
        },
        "oneOf": [
          {
            "properties": {
              "status": {"const": "available"},
              "projection": {"type": "string", "minLength": 1},
              "generation": {"type": "string", "pattern": "^(?:cipv1|sr1)-[a-f0-9]{64}$"},
              "endpoints": {"minItems": 1}
            }
          },
          {
            "properties": {
              "status": {"const": "unavailable"},
              "generation": {"type": "null"},
              "endpoints": {"maxItems": 0}
            }
          },
          {
            "properties": {
              "status": {"const": "separate_authority"},
              "projection": {"type": "string", "minLength": 1},
              "generation": {"type": "null"},
              "endpoints": {"minItems": 1}
            }
          }
        ],
        "additionalProperties": false
      },
      "PublicIntegration": {
        "type": "object",
        "required": ["slug", "source_slug", "name", "kind", "capabilities", "public_read", "egress_policy", "transport", "official_url", "license", "attribution_required", "reuse_conditions", "policy_effective_date", "reviewed_at", "catalog_version"],
        "properties": {
          "slug": {"type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
          "source_slug": {"type": "string", "description": "Canonical source slug from the active public-source catalog."},
          "name": {"type": "string"},
          "kind": {"type": "string"},
          "capabilities": {"type": "array", "items": {"type": "string"}},
          "public_read": {"type": "boolean", "description": "True only when transport.status is available or separate_authority; never derived from legal permission alone."},
          "egress_policy": {"$ref": "#/components/schemas/PublicIntegrationEgressPolicy"},
          "transport": {"$ref": "#/components/schemas/PublicIntegrationTransport"},
          "official_url": {"type": "string", "format": "uri"},
          "license": {"type": "string"},
          "license_url": {"type": ["string", "null"], "format": "uri"},
          "attribution_required": {"type": "boolean"},
          "attribution_text": {"type": ["string", "null"]},
          "reuse_conditions": {"type": "string", "description": "Condiciones de reutilizacion aplicables a esta integracion publica."},
          "policy_effective_date": {"type": "string", "format": "date"},
          "reviewed_at": {"type": "string", "format": "date"},
          "catalog_version": {"type": "string"},
          "coverage": {
            "$ref": "#/components/schemas/PublicIntegrationCoverage"
          }
        },
        "additionalProperties": false
      },
      "IntegrationListResponse": {
        "type": "object",
        "required": ["schema_version", "source_catalog_version", "count", "items", "contract", "_source_catalog", "_data_sources_used"],
        "properties": {
          "schema_version": {"type": "string"},
          "source_catalog_version": {"type": "string"},
          "count": {"type": "integer"},
          "items": {"type": "array", "items": {"$ref": "#/components/schemas/PublicIntegration"}},
          "contract": {
            "$ref": "#/components/schemas/PublicIntegrationContract"
          },
          "_source_catalog": {"$ref": "#/components/schemas/SourceCatalogEnvelope"},
          "_data_sources_used": {"type": "array", "items": {"$ref": "#/components/schemas/PublicSourcePolicyMetadata"}},
          "_attributions": {"type": "object", "additionalProperties": {"type": "string"}}
        },
        "additionalProperties": false
      },
      "IntegrationDetailResponse": {
        "type": "object",
        "required": ["schema_version", "source_catalog_version", "integration", "contract", "_source_catalog", "_data_sources_used"],
        "properties": {
          "schema_version": {"type": "string"},
          "source_catalog_version": {"type": "string"},
          "integration": {"$ref": "#/components/schemas/PublicIntegration"},
          "contract": {"$ref": "#/components/schemas/PublicIntegrationContract"},
          "_source_catalog": {"$ref": "#/components/schemas/SourceCatalogEnvelope"},
          "_data_sources_used": {"type": "array", "items": {"$ref": "#/components/schemas/PublicSourcePolicyMetadata"}},
          "_attributions": {"type": "object", "additionalProperties": {"type": "string"}}
        },
        "additionalProperties": false
      },
      "SearchResponse": {
        "type": "object",
        "required": ["query", "count", "items"],
        "properties": {
          "query": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CompanySearchItem"
            }
          }
        }
      },
      "CompanySearchItem": {
        "type": "object",
        "required": ["slug", "name", "cif", "acts_count"],
        "properties": {
          "slug": {
            "type": "string",
            "example": "mercadona-sa"
          },
          "name": {
            "type": "string",
            "example": "MERCADONA SA"
          },
          "cif": {
            "type": "string",
            "example": "A46103834"
          },
          "acts_count": {
            "type": "integer"
          },
          "last_seen": {
            "type": ["string", "null"]
          },
          "province": {"type": ["string", "null"]},
          "cnae_code": {"type": ["string", "null"]},
          "cnae_section": {"type": ["string", "null"]},
          "capital_cents": {"type": ["integer", "null"], "minimum": 0},
          "first_seen": {"type": ["string", "null"]},
          "matched_alias": {
            "type": "string",
            "description": "Present only when an exact safe alias was matched; slug is always canonical."
          },
          "aliases": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "GraphEdge": {
        "type": "object",
        "properties": {
          "slug": {"type": ["string", "null"], "example": "endesa-sa"},
          "name": {"type": "string", "example": "ENDESA SA"},
          "rel_type": {"type": "string", "example": "IS_DIRECTLY_CONSOLIDATED_BY"},
          "source_slug": {"type": "string", "description": "Canonical dataset slug authorized by the active source policy."}
        }
      },
      "CompanyGraphResponse": {
        "type": "object",
        "required": ["schema_version", "canonical_url", "center", "parents", "children", "coverage", "as_of"],
        "properties": {
          "schema_version": {"type": "string", "example": "1"},
          "canonical_url": {"type": "string", "format": "uri"},
          "center": {
            "type": "object",
            "properties": {
              "slug": {"type": "string"},
              "name": {"type": "string"},
              "cif": {"type": "string"}
            }
          },
          "parents":  {"type": "array", "items": {"$ref": "#/components/schemas/GraphEdge"}},
          "children": {"type": "array", "items": {"$ref": "#/components/schemas/GraphEdge"}},
          "counts": {
            "type": "object",
            "properties": {
              "parents":  {"type": "integer"},
              "children": {"type": "integer"}
            }
          },
          "coverage": {"type": "object", "additionalProperties": {"type": "string"}},
          "_source_catalog": {
            "$ref": "#/components/schemas/SourceCatalogEnvelope"
          },
          "as_of":       {"type": "string", "format": "date", "example": "2026-05-18"},
          "ttl_seconds": {"type": "integer", "const": 0, "example": 0}
        }
      },
      "PersonPublicProjectionMetadata": {
        "type": "object",
        "required": ["name", "schema_version", "contract_sha256", "source_generation", "content_sha256", "projected_at"],
        "properties": {
          "name": {"type": "string", "const": "person_public_v1"},
          "schema_version": {"type": "string", "const": "1.0"},
          "contract_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
          "source_generation": {"type": "string", "pattern": "^cpv2-[a-f0-9]{64}$"},
          "content_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
          "projected_at": {"type": "string", "format": "date-time"}
        },
        "additionalProperties": false
      },
      "PersonDocumentaryPosition": {
        "type": "object",
        "required": ["company", "company_name", "company_slug", "cif", "role", "since", "until", "documentary_status", "vigency_verified", "source_slug", "source_url"],
        "properties": {
          "company": {"type": "string", "minLength": 1},
          "company_name": {"type": "string", "minLength": 1},
          "company_slug": {"type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
          "cif": {"type": "string", "description": "Admitted legal-entity CIF; never a natural-person identifier."},
          "role": {"type": ["string", "null"]},
          "since": {"type": ["string", "null"], "format": "date"},
          "until": {"type": ["string", "null"], "format": "date"},
          "documentary_status": {"type": "string", "enum": ["open_documentary_mention", "historical_documentary_mention"]},
          "vigency_verified": {"type": "boolean", "const": false},
          "source_slug": {"type": "string", "const": "borme"},
          "source_url": {"type": "string", "format": "uri", "const": "https://www.boe.es/diario_borme/"}
        },
        "additionalProperties": false
      },
      "PersonGraphCompany": {
        "type": "object",
        "required": ["slug", "name", "rel_type", "role", "since", "until", "documentary_status", "vigency_verified", "source_slug"],
        "properties": {
          "slug": {"type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
          "name": {"type": "string", "minLength": 1},
          "rel_type": {"type": "string", "const": "OFFICER_OF"},
          "role": {"type": "string"},
          "since": {"type": ["string", "null"], "format": "date"},
          "until": {"type": ["string", "null"], "format": "date"},
          "documentary_status": {"type": "string", "enum": ["open_documentary_mention", "historical_documentary_mention"]},
          "vigency_verified": {"type": "boolean", "const": false},
          "source_slug": {"type": "string", "const": "borme"}
        },
        "additionalProperties": false
      },
      "PersonGraphResponse": {
        "type": "object",
        "required": ["schema_version", "status", "canonical_url", "center", "companies", "coverage", "projection", "as_of", "ttl_seconds", "subject_type", "identity_resolution", "_legal_notice", "_source_catalog", "_data_sources_used"],
        "properties": {
          "schema_version": {"type": "string", "const": "person_graph_v1"},
          "status": {"type": "string", "const": "available"},
          "canonical_url": {"type": "string", "format": "uri"},
          "center": {
            "type": "object",
            "required": ["slug", "name", "companies_count", "first_seen", "last_seen", "subject_type", "identity_resolution"],
            "properties": {
              "slug": {"type": "string"},
              "name": {"type": "string"},
              "companies_count": {"type": "integer", "minimum": 1},
              "first_seen": {"type": ["string", "null"], "format": "date"},
              "last_seen": {"type": ["string", "null"], "format": "date"},
              "subject_type": {"type": "string", "const": "person_documentary_mentions"},
              "identity_resolution": {"type": "string", "const": "not_performed"}
            },
            "additionalProperties": false
          },
          "companies": {"type": "array", "maxItems": 50, "items": {"$ref": "#/components/schemas/PersonGraphCompany"}},
          "coverage": {
            "type": "object",
            "required": ["borme_officer_edges", "external_person_enrichment"],
            "properties": {
              "borme_officer_edges": {"type": "string", "const": "included"},
              "external_person_enrichment": {"type": "string", "const": "withheld_not_in_person_public_v1"}
            },
            "additionalProperties": false
          },
          "projection": {"$ref": "#/components/schemas/PersonPublicProjectionMetadata"},
          "as_of": {"type": "string", "format": "date"},
          "ttl_seconds": {"type": "integer", "const": 0},
          "subject_type": {"type": "string", "const": "person_documentary_mentions"},
          "identity_resolution": {"type": "string", "const": "not_performed"},
          "_legal_notice": {"type": "string", "minLength": 1},
          "_source_catalog": {"$ref": "#/components/schemas/SourceCatalogEnvelope"},
          "_data_sources_used": {"type": "array", "minItems": 1, "items": {"$ref": "#/components/schemas/PublicSourcePolicyMetadata"}},
          "_attributions": {"type": "object", "additionalProperties": {"type": "string"}}
        },
        "additionalProperties": false
      },
      "ErrorResponse": {
        "type": "object",
        "description": "Closed compatibility envelope for public/account errors. Route-specific schemas narrow these fields further where required.",
        "required": ["error"],
        "properties": {
          "error": {"type": "string", "minLength": 1},
          "message": {"type": "string"},
          "detail": {"type": "string"},
          "code": {"type": "string"},
          "status": {"type": ["integer", "string"]},
          "projection": {"type": "string"},
          "reason": {"type": "string"},
          "source_catalog_version": {"type": "string"},
          "allowed_parameters": {"type": "array", "uniqueItems": true, "items": {"type": "string"}},
          "slug": {"type": "string"},
          "key": {"type": "string"},
          "maximum": {"type": "integer", "minimum": 1},
          "parameter": {"type": "string"},
          "fields": {"type": "array", "items": {"type": "string"}},
          "max_bytes": {"type": "integer", "minimum": 1},
          "allowed": {"type": "array", "items": {"$ref": "#/components/schemas/JsonValue"}},
          "valid": {"type": "array", "items": {"$ref": "#/components/schemas/JsonValue"}},
          "date": {"type": "string"},
          "login_url": {"type": "string"},
          "plan": {"type": "string"},
          "limited_by": {"type": "string", "enum": ["minute", "day"]},
          "daily_limit": {"type": "integer", "minimum": 1},
          "reset_at": {"type": "integer", "minimum": 1},
          "reset_at_human": {"type": "string", "format": "date-time"},
          "retry_after_s": {"type": "integer", "minimum": 1},
          "retry_after": {"type": "integer", "minimum": 1},
          "upgrade": {"type": "string", "format": "uri"},
          "upgrade_url": {"type": "string"},
          "action": {"type": "string"},
          "limit": {"type": "integer", "minimum": 0},
          "remaining": {"type": "integer", "minimum": 0},
          "needed": {"type": "integer", "minimum": 0},
          "shortfall": {"type": "integer", "minimum": 0},
          "ok": {"type": "boolean"},
          "_alias_of": {"type": "string"}
        },
        "additionalProperties": false
      },
      "ProjectionUnavailableError": {
        "type": "object",
        "description": "Fail-closed projection outage. Clients must not reinterpret this response as an empty or negative result.",
        "required": [
          "error",
          "detail",
          "projection"
        ],
        "properties": {
          "error": {
            "type": "string",
            "const": "projection_unavailable"
          },
          "detail": {
            "type": "string"
          },
          "projection": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "LegalLicenseFields": {
        "type": "object",
        "description": "License/attribution/disclaimer envelope present in every legal-layer response. The legal corpus is consolidated BOE text re-used under Ley 37/2007 (NOT CC BY 4.0).",
        "properties": {
          "license": {"type": "string", "example": "BOE — Ley 37/2007 (reutilización de la información del sector público)"},
          "license_url": {"type": "string", "format": "uri", "example": "https://www.boe.es/informacion/aviso_legal/index.php"},
          "attribution": {"type": "string", "example": "Texto consolidado del Boletín Oficial del Estado (BOE), estructurado por OpenMercantil. La versión oficial y auténtica es la publicada en boe.es."},
          "disclaimer": {"type": "string", "example": "Contenido meramente informativo. No constituye asesoramiento jurídico ni sustituye al texto oficial consolidado del BOE."},
          "generated_at": {"type": "string", "format": "date-time"}
        }
      },
      "LegalNormSummary": {
        "type": "object",
        "properties": {
          "slug": {"type": "string", "example": "ley-de-sociedades-de-capital"},
          "title": {"type": "string"},
          "short_name": {"type": ["string", "null"], "example": "LSC"},
          "norm_type": {"type": "string", "example": "real_decreto_legislativo"},
          "norm_type_label": {"type": "string", "example": "Real Decreto Legislativo"},
          "in_force": {"type": "boolean"},
          "url": {"type": "string", "format": "uri"},
          "api_url": {"type": "string", "format": "uri"}
        }
      },
      "LegalNormFull": {
        "type": "object",
        "properties": {
          "slug": {"type": "string"},
          "title": {"type": "string"},
          "short_name": {"type": ["string", "null"]},
          "norm_type": {"type": "string"},
          "norm_type_label": {"type": "string"},
          "boe_id": {"type": ["string", "null"], "example": "BOE-A-2010-10544"},
          "eli": {"type": ["string", "null"], "example": "https://www.boe.es/eli/es/rdlg/2010/07/02/1"},
          "official_url": {"type": "string", "format": "uri", "description": "Canonical, authentic source at boe.es."},
          "in_force": {"type": "boolean"},
          "repealed_by": {"type": ["string", "null"]},
          "summary": {"type": "string"},
          "date_published": {"type": ["string", "null"], "format": "date"},
          "date_modified": {"type": "string", "format": "date"},
          "url": {"type": "string", "format": "uri"}
        }
      },
      "LegalKeyArticle": {
        "type": "object",
        "properties": {
          "article_num": {"type": "string", "example": "318"},
          "label": {"type": "string"},
          "rule": {"type": "string", "description": "Plain-language rule extracted from the article."},
          "has_text": {"type": "boolean", "description": "Whether the consolidated BOE text is seeded for this article."},
          "url": {"type": "string", "format": "uri"},
          "api_url": {"type": "string", "format": "uri"}
        }
      },
      "LegalRegulatedAct": {
        "type": "object",
        "description": "BORME act type governed by this norm (law→data bridge).",
        "properties": {
          "act_type": {"type": "string", "example": "ampliacion-capital"},
          "label": {"type": "string"},
          "articles": {"type": "string", "example": "LSC arts. 295-316"},
          "microtext": {"type": "string"},
          "url": {"type": "string", "format": "uri", "description": "Bridge page listing real companies with this act (/ley/{slug}/empresas)."}
        }
      },
      "LegalCitableFact": {
        "type": ["object", "null"],
        "description": "Single atomic, verbatim-citable fact for AI answers (GEO envelope).",
        "properties": {
          "statement": {"type": "string"},
          "source": {"type": "string", "example": "BOE — texto consolidado (Ley 37/2007)"},
          "source_url": {"type": "string", "format": "uri"},
          "date": {"type": "string", "format": "date"},
          "verify_url": {"type": "string", "format": "uri"}
        }
      },
      "LegalNormsIndexResponse": {
        "allOf": [
          {
            "type": "object",
            "required": ["layer", "count", "norms"],
            "properties": {
              "layer": {"type": "string", "example": "derecho-mercantil"},
              "count": {"type": "integer", "example": 48},
              "norms": {"type": "array", "items": {"$ref": "#/components/schemas/LegalNormSummary"}},
              "docs": {"type": "string", "format": "uri", "example": "https://openmercantil.es/leyes"}
            }
          },
          {"$ref": "#/components/schemas/LegalLicenseFields"}
        ]
      },
      "LegalNormResponse": {
        "allOf": [
          {
            "type": "object",
            "required": ["norm"],
            "properties": {
              "norm": {"$ref": "#/components/schemas/LegalNormFull"},
              "key_articles": {"type": "array", "items": {"$ref": "#/components/schemas/LegalKeyArticle"}},
              "regulated_acts": {"type": "array", "items": {"$ref": "#/components/schemas/LegalRegulatedAct"}},
              "citable_fact": {"$ref": "#/components/schemas/LegalCitableFact"}
            }
          },
          {"$ref": "#/components/schemas/LegalLicenseFields"}
        ]
      },
      "LegalArticleResponse": {
        "allOf": [
          {
            "type": "object",
            "required": ["article_num", "body_html"],
            "properties": {
              "norm": {
                "type": ["object", "null"],
                "properties": {
                  "slug": {"type": "string"},
                  "title": {"type": "string"},
                  "short_name": {"type": ["string", "null"]},
                  "official_url": {"type": "string", "format": "uri"}
                }
              },
              "article_num": {"type": "string", "example": "318"},
              "title": {"type": "string", "example": "Artículo 318. El acuerdo de reducción del capital social."},
              "body_html": {"type": "string", "description": "Consolidated article text (HTML) from the BOE, re-used under Ley 37/2007."},
              "eli_anchor": {"type": "string", "example": "https://www.boe.es/eli/es/rdlg/2010/07/02/1/con#a318"},
              "version_date": {"type": ["string", "null"], "format": "date"},
              "url": {"type": "string", "format": "uri"}
            }
          },
          {"$ref": "#/components/schemas/LegalLicenseFields"}
        ]
      },
      "LegalActMapEntry": {
        "allOf": [
          {
            "type": "object",
            "properties": {
              "act_type": {"type": "string", "example": "ampliacion-capital"},
              "norm_slug": {"type": "string"},
              "norm_api_url": {"type": ["string", "null"], "format": "uri"},
              "articles": {"type": "string"},
              "microtext": {"type": "string"},
              "concept_slug": {"type": ["string", "null"]}
            }
          },
          {"$ref": "#/components/schemas/LegalLicenseFields"}
        ]
      },
      "LegalActMapResponse": {
        "allOf": [
          {
            "type": "object",
            "required": ["layer", "count", "act_map"],
            "properties": {
              "layer": {"type": "string", "example": "puente-acto-norma"},
              "count": {"type": "integer", "example": 22},
              "act_map": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "act_type": {"type": "string"},
                    "norm_slug": {"type": "string"},
                    "norm_api_url": {"type": ["string", "null"], "format": "uri"},
                    "articles": {"type": "string"},
                    "microtext": {"type": "string"},
                    "concept_slug": {"type": ["string", "null"]}
                  }
                }
              }
            }
          },
          {"$ref": "#/components/schemas/LegalLicenseFields"}
        ]
      },
      "SourceCatalogEnvelope": {
        "type": "object",
        "required": [
          "catalog_version",
          "policy_fingerprint",
          "sources"
        ],
        "properties": {
          "catalog_version": {
            "type": "string"
          },
          "policy_fingerprint": {
            "type": "string"
          },
          "policy_effective_date": {
            "type": "string",
            "format": "date"
          },
          "sources": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/PublicSourcePolicyMetadata"
            }
          }
        },
        "additionalProperties": false
      },
      "CompanyIdentity": {
        "type": "object",
        "description": "Stable company identity fields. Historical report builders may append documented BORME fields.",
        "properties": {
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "cif": {
            "type": [
              "string",
              "null"
            ]
          },
          "province": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": [
              "string",
              "null"
            ]
          },
          "status_detail": {
            "type": [
              "string",
              "null"
            ]
          },
          "status_date": {
            "type": [
              "string",
              "null"
            ]
          },
          "cnae": {
            "type": [
              "string",
              "null"
            ]
          },
          "cnae_source": {
            "type": [
              "string",
              "null"
            ]
          },
          "first_seen": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_seen": {
            "type": [
              "string",
              "null"
            ]
          },
          "acts_count": {
            "type": "integer"
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "BormeEvent": {
        "type": "object",
        "description": "Sanitized documentary BORME event; additional source fields remain backward compatible.",
        "properties": {
          "id": {
            "type": [
              "string",
              "null"
            ]
          },
          "date": {
            "type": [
              "string",
              "null"
            ]
          },
          "publish_date": {
            "type": [
              "string",
              "null"
            ]
          },
          "type": {
            "type": [
              "string",
              "null"
            ]
          },
          "act_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "text": {
            "type": [
              "string",
              "null"
            ]
          },
          "province": {
            "type": [
              "string",
              "null"
            ]
          },
          "source": {
            "type": [
              "string",
              "null"
            ]
          },
          "source_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "OfficerDocumentaryMention": {
        "type": "object",
        "description": "Documentary officer mention. It never contains DNI, contact details or a personal address.",
        "properties": {
          "name": {
            "type": "string"
          },
          "person_slug": {
            "type": [
              "string",
              "null"
            ]
          },
          "role": {
            "type": [
              "string",
              "null"
            ]
          },
          "appointed_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "ended_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "source": {
            "type": [
              "string",
              "null"
            ]
          },
          "source_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "CompanyCompareEntity": {
        "type": "object",
        "description": "Exact allowlisted company_public_v2 row used by a comparison. No report, officer, status, score, account or raw fields are permitted.",
        "required": [
          "slug", "name", "cif", "province", "cnae_code", "cnae_section",
          "capital_cents", "first_seen", "last_seen", "acts_count"
        ],
        "properties": {
          "slug": {
            "type": "string",
            "maxLength": 240,
            "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
          },
          "name": {"type": "string", "minLength": 1},
          "cif": {
            "type": "string",
            "pattern": "^[ABCDEFGHJNPQRSUVW][0-9]{7}[0-9A-J]$"
          },
          "province": {"type": ["string", "null"]},
          "cnae_code": {"type": ["string", "null"]},
          "cnae_section": {"type": ["string", "null"]},
          "capital_cents": {"type": ["integer", "null"], "minimum": 0},
          "first_seen": {"type": ["string", "null"]},
          "last_seen": {"type": ["string", "null"]},
          "acts_count": {"type": "integer", "minimum": 0}
        },
        "additionalProperties": false
      },
      "CompanyCompareAuthority": {
        "type": "object",
        "description": "Public generation authority. Internal paths and identity/content/contract/policy fingerprints are deliberately omitted.",
        "required": [
          "projection", "schema_version", "builder_version", "source_generation",
          "projected_at", "row_count", "cache_namespace"
        ],
        "properties": {
          "projection": {"type": "string", "const": "company_public_v2"},
          "schema_version": {"type": "string", "minLength": 1},
          "builder_version": {"type": "string", "minLength": 1},
          "source_generation": {
            "type": "string",
            "pattern": "^cpv2-[a-f0-9]{64}$"
          },
          "projected_at": {"type": "string", "minLength": 1},
          "row_count": {"type": "integer", "minimum": 1},
          "cache_namespace": {
            "type": "string",
            "minLength": 1,
            "maxLength": 240,
            "pattern": "^[a-z0-9_.:-]+$"
          }
        },
        "additionalProperties": false
      },
      "CompanyCompareResponse": {
        "type": "object",
        "description": "Stable company_compare_v1 response. All three arrays are index-aligned and sorted lexicographically by canonical slug.",
        "required": [
          "status", "projection", "projection_status", "requested_slugs",
          "canonical_slugs", "companies", "authority"
        ],
        "properties": {
          "status": {"type": "string", "const": "available"},
          "projection": {"type": "string", "const": "company_compare_v1"},
          "projection_status": {"type": "string", "const": "available"},
          "requested_slugs": {
            "type": "array",
            "minItems": 2,
            "maxItems": 2,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "maxLength": 240,
              "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
            }
          },
          "canonical_slugs": {
            "type": "array",
            "minItems": 2,
            "maxItems": 2,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "maxLength": 240,
              "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
            }
          },
          "companies": {
            "type": "array",
            "minItems": 2,
            "maxItems": 2,
            "items": {"$ref": "#/components/schemas/CompanyCompareEntity"}
          },
          "authority": {"$ref": "#/components/schemas/CompanyCompareAuthority"}
        },
        "additionalProperties": false
      },
      "CompanyCompareInvalidRequest": {
        "type": "object",
        "required": ["error", "detail"],
        "properties": {
          "error": {"type": "string", "const": "invalid_parameter"},
          "detail": {"type": "string"}
        },
        "additionalProperties": false
      },
      "CompanyCompareNotFound": {
        "type": "object",
        "description": "Neutral absence envelope; it does not identify which input was absent or withheld.",
        "required": ["error"],
        "properties": {
          "error": {"type": "string", "const": "not_found"}
        },
        "additionalProperties": false
      },
      "CompanyCompareLegalUnavailable": {
        "type": "object",
        "description": "The active public-source policy could not authorize BORME before comparison admission.",
        "required": ["error", "detail", "source_catalog_version"],
        "properties": {
          "error": {"type": "string", "const": "legal_layer_unavailable"},
          "detail": {"type": "string"},
          "source_catalog_version": {"type": "string", "minLength": 1}
        },
        "additionalProperties": false
      },
      "CompanyReport": {
        "type": "object",
        "description": "Sanitized company report. The stable envelope is explicit; versioned BORME report fields may be added.",
        "properties": {
          "company": {
            "$ref": "#/components/schemas/CompanyIdentity"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BormeEvent"
            }
          },
          "officers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OfficerDocumentaryMention"
            }
          },
          "summary": {
            "type": "object",
            "description": "Versioned aggregate fields emitted by the report artifact.",
            "properties": {},
            "additionalProperties": {
              "$ref": "#/components/schemas/JsonValue"
            }
          },
          "_source_catalog": {
            "$ref": "#/components/schemas/SourceCatalogEnvelope"
          },
          "_data_sources_used": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicSourcePolicyMetadata"
            }
          },
          "_attributions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "CompanyEventsResponse": {
        "type": "object",
        "required": [
          "slug",
          "year",
          "page",
          "page_size",
          "total",
          "pages",
          "items"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "year": {
            "type": "string",
            "pattern": "^\\d{4}$"
          },
          "page": {
            "type": "integer"
          },
          "page_size": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "pages": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BormeEvent"
            },
            "maxItems": 100
          }
        },
        "additionalProperties": false
      },
      "OfficerList": {
        "type": "array",
        "maxItems": 500,
        "items": {
          "$ref": "#/components/schemas/OfficerDocumentaryMention"
        }
      },
      "CompanyProcurementResponse": {
        "type": "object",
        "required": [
          "schema_version",
          "slug",
          "count",
          "items",
          "page",
          "monetary_rollup",
          "rollup_policy"
        ],
        "properties": {
          "schema_version": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TenderNotice"
            },
            "maxItems": 100
          },
          "page": {
            "type": "object",
            "required": [
              "limit",
              "has_more"
            ],
            "properties": {
              "limit": {
                "type": "integer"
              },
              "has_more": {
                "type": "boolean"
              }
            },
            "additionalProperties": false
          },
          "monetary_rollup": {
            "type": "null"
          },
          "rollup_policy": {
            "type": "string"
          },
          "coverage": {
            "$ref": "#/components/schemas/TenderCoverage"
          },
          "attribution": {
            "type": "string"
          },
          "disclaimer": {
            "type": "string"
          },
          "_alias_of": {
            "type": "string"
          },
          "_source_catalog": {
            "$ref": "#/components/schemas/SourceCatalogEnvelope"
          }
        },
        "additionalProperties": false
      },
      "CompanyIntegrationAcquisitionCoverage": {
        "type": "object",
        "description": "Attested acquisition boundary for one governed source package. Completeness applies only to this exact bounded scope; complete_history_claimed and source_snapshot_claimed are always false, so this metadata never asserts complete historical or upstream snapshot coverage.",
        "required": ["scope", "declared_scope_complete", "complete_history_claimed", "source_snapshot_claimed", "window_start", "window_end", "relative_window_days", "source_as_of", "identity_seed_subject_count", "request_count", "partition_count", "source_package_schema", "source_package_manifest_sha256", "source_fragment_schema", "source_fragment_sha256", "source_authority_binding_sha256", "coverage_sha256"],
        "properties": {
          "scope": {"type": "string", "enum": ["bounded_newest_first_page_prefix", "directory_snapshot_plus_relative_event_window", "publication_date_window_page_walk", "exact_identity_seed_lookup_snapshot"]},
          "declared_scope_complete": {"type": "boolean", "const": true, "description": "All partitions declared by this bounded acquisition scope were captured; this is not a complete-history claim."},
          "complete_history_claimed": {"type": "boolean", "const": false},
          "source_snapshot_claimed": {"type": "boolean", "const": false},
          "window_start": {"type": ["string", "null"], "format": "date"},
          "window_end": {"type": ["string", "null"], "format": "date"},
          "relative_window_days": {"type": ["integer", "null"], "minimum": 1},
          "source_as_of": {"type": ["string", "null"], "format": "date"},
          "identity_seed_subject_count": {"type": "integer", "minimum": 1},
          "request_count": {"type": "integer", "minimum": 1},
          "partition_count": {"type": "integer", "minimum": 1},
          "source_package_schema": {"type": "string", "enum": ["openmercantil-bdns-reingest-package/v2", "openmercantil-cnmv-reingest-package/v2", "openmercantil-ted-reingest-package/v2", "openmercantil-wikidata-reingest-package/v2"]},
          "source_package_manifest_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
          "source_fragment_schema": {"type": "string", "enum": ["openmercantil-bdns-reingest-source-fragment/v2", "openmercantil-cnmv-reingest-source-fragment/v2", "openmercantil-ted-reingest-source-fragment/v2", "openmercantil-wikidata-reingest-source-fragment/v2"]},
          "source_fragment_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
          "source_authority_binding_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
          "coverage_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$", "description": "Digest of the producer-declared bounded coverage object; it is integrity evidence, not proof of complete history."}
        },
        "additionalProperties": false
      },
      "CompanyIntegrationSourceMetadata": {
        "type": "object",
        "description": "Projection-bound legal metadata plus the exact governed acquisition boundary for a company integration source.",
        "required": ["slug", "name", "license", "license_url", "attribution_required", "attribution_text", "official_url", "reuse_conditions", "policy_effective_date", "reviewed_at", "data_updated_at", "catalog_version", "acquisition_coverage"],
        "properties": {
          "slug": {"type": "string", "enum": ["bdns", "cnmv", "ted_eu", "wikidata"]},
          "name": {"type": "string", "minLength": 1},
          "license": {"type": "string", "minLength": 1},
          "license_url": {"type": ["string", "null"], "format": "uri"},
          "attribution_required": {"type": "boolean"},
          "attribution_text": {"type": ["string", "null"]},
          "official_url": {"type": "string", "format": "uri"},
          "reuse_conditions": {"type": "string", "minLength": 1},
          "policy_effective_date": {"type": "string", "format": "date"},
          "reviewed_at": {"type": "string", "format": "date"},
          "data_updated_at": {"type": ["string", "null"], "format": "date-time"},
          "catalog_version": {"type": "string", "minLength": 1},
          "acquisition_coverage": {"$ref": "#/components/schemas/CompanyIntegrationAcquisitionCoverage"}
        },
        "additionalProperties": false
      },
      "CompanyIntegrationProjection": {
        "type": "object",
        "required": ["name", "schema_version", "builder_version", "generation"],
        "properties": {
          "name": {"type": "string", "const": "company_integrations_public_v1"},
          "schema_version": {"type": "string", "const": "1.3"},
          "builder_version": {"type": "string", "const": "1.4.0"},
          "generation": {"type": "string", "pattern": "^cipv1-[a-f0-9]{64}$"}
        },
        "additionalProperties": false
      },
      "GrantRecord": {
        "type": "object",
        "description": "Minimized, attested BDNS row. award_amount_cents is an awarded amount, never proof of payment.",
        "required": ["bdns_code", "granting_body", "title", "award_year", "instrument", "award_amount_cents", "award_amount_currency", "amount_quality", "amount_semantics"],
        "properties": {
          "bdns_code": {"type": "string"},
          "granting_body": {"type": "string"},
          "title": {"type": "string"},
          "award_year": {"type": ["integer", "null"], "minimum": 1900},
          "instrument": {"type": ["string", "null"]},
          "award_amount_cents": {"type": ["integer", "null"], "minimum": 1},
          "award_amount_currency": {"type": ["string", "null"], "enum": ["EUR", null]},
          "amount_quality": {"type": "string", "enum": ["reported_positive_cents", "unknown_zero_ambiguous", "unknown_missing"]},
          "amount_semantics": {"type": "string", "const": "awarded_not_payment"}
        },
        "additionalProperties": false
      },
      "CompanyGrantsResponse": {
        "type": "object",
        "description": "Generation-bound BDNS view. count is the total projected row count; returned_count is the bounded slice length. No monetary rollup is emitted.",
        "required": ["projection_status", "projection", "slug", "cif", "complete_bounded_projection", "coverage_status", "source_metadata", "coverage_notice", "count", "returned_count", "items", "amount_notice", "_source_catalog", "_data_sources_used"],
        "properties": {
          "projection_status": {"type": "string", "const": "available"},
          "projection": {"$ref": "#/components/schemas/CompanyIntegrationProjection"},
          "slug": {"type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
          "cif": {"type": "string", "pattern": "^[ABCDEFGHJNPQRSUVW][0-9]{7}[0-9A-J]$"},
          "complete_bounded_projection": {"type": "boolean", "const": true},
          "coverage_status": {"type": "string", "enum": ["available", "empty"]},
          "source_metadata": {"$ref": "#/components/schemas/CompanyIntegrationSourceMetadata"},
          "coverage_notice": {"type": "string"},
          "count": {"type": "integer", "minimum": 0, "maximum": 200},
          "returned_count": {"type": "integer", "minimum": 0, "maximum": 200},
          "items": {"type": "array", "maxItems": 200, "items": {"$ref": "#/components/schemas/GrantRecord"}},
          "amount_notice": {"type": "string"},
          "_source_catalog": {"$ref": "#/components/schemas/SourceCatalogEnvelope"},
          "_data_sources_used": {"type": "array", "items": {"$ref": "#/components/schemas/PublicSourcePolicyMetadata"}},
          "_attributions": {"type": "object", "additionalProperties": {"type": "string"}}
        },
        "additionalProperties": false
      },
      "CompanySourceCoverageRecord": {
        "type": "object",
        "required": ["source_slug", "coverage_status", "count", "metadata"],
        "properties": {
          "source_slug": {"type": "string", "enum": ["bdns", "cnmv", "ted_eu", "wikidata"]},
          "coverage_status": {"type": "string", "enum": ["available", "empty"]},
          "count": {"type": "integer", "minimum": 0, "maximum": 200},
          "metadata": {"$ref": "#/components/schemas/CompanyIntegrationSourceMetadata"}
        },
        "additionalProperties": false
      },
      "CompanySourcesResponse": {
        "type": "object",
        "description": "Coverage summary for exactly four sources in one company_integrations_public_v1 generation. It is not the global legal catalog.",
        "required": ["projection_status", "projection", "slug", "cif", "complete_bounded_projection", "coverage_status", "sources_count", "available_sources_count", "sources", "coverage_notice", "_source_catalog", "_data_sources_used"],
        "properties": {
          "projection_status": {"type": "string", "const": "available"},
          "projection": {"$ref": "#/components/schemas/CompanyIntegrationProjection"},
          "slug": {"type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
          "cif": {"type": "string", "pattern": "^[ABCDEFGHJNPQRSUVW][0-9]{7}[0-9A-J]$"},
          "complete_bounded_projection": {"type": "boolean", "const": true},
          "coverage_status": {"type": "string", "enum": ["available", "empty"]},
          "sources_count": {"type": "integer", "const": 4},
          "available_sources_count": {"type": "integer", "minimum": 0, "maximum": 4},
          "sources": {
            "type": "array",
            "minItems": 4,
            "maxItems": 4,
            "items": {"$ref": "#/components/schemas/CompanySourceCoverageRecord"}
          },
          "coverage_notice": {"type": "string"},
          "_source_catalog": {"$ref": "#/components/schemas/SourceCatalogEnvelope"},
          "_data_sources_used": {"type": "array", "items": {"$ref": "#/components/schemas/PublicSourcePolicyMetadata"}},
          "_attributions": {"type": "object", "additionalProperties": {"type": "string"}}
        },
        "additionalProperties": false
      },
      "DocumentarySanction": {
        "type": "object",
        "description": "Sanitized documentary sanction record; appearance does not imply current liability.",
        "properties": {
          "source": {
            "type": [
              "string",
              "null"
            ]
          },
          "date": {
            "type": [
              "string",
              "null"
            ]
          },
          "authority": {
            "type": [
              "string",
              "null"
            ]
          },
          "summary": {
            "type": [
              "string",
              "null"
            ]
          },
          "official_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "status": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "CompanySanctionsResponse": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentarySanction"
            }
          },
          "source": {
            "type": [
              "string",
              "null"
            ]
          },
          "note": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "DailySummary": {
        "type": "object",
        "description": "BORME daily artifact. Stable counters are explicit; grouping fields may evolve with the artifact version.",
        "properties": {
          "date": {
            "type": [
              "string",
              "null"
            ]
          },
          "count": {
            "type": "integer"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BormeEvent"
            }
          },
          "provinces": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            }
          },
          "types": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            }
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "BormeFact": {
        "type": "object",
        "description": "Sanitized structured BORME fact; DNI/NIE is redacted before caching.",
        "properties": {
          "fact_type": {
            "type": "string"
          },
          "publish_date": {
            "type": [
              "string",
              "null"
            ]
          },
          "event_date": {
            "type": [
              "string",
              "null"
            ]
          },
          "text_value": {
            "type": [
              "string",
              "null"
            ]
          },
          "person_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "role": {
            "type": [
              "string",
              "null"
            ]
          },
          "source_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "CompanyFactsResponse": {
        "type": "object",
        "required": [
          "slug",
          "count",
          "has_more",
          "facts",
          "summary",
          "source"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "has_more": {
            "type": "boolean"
          },
          "facts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BormeFact"
            },
            "maxItems": 200
          },
          "summary": {
            "type": "object",
            "description": "Closed summary derived from the same hash-attested company report as the returned facts.",
            "required": ["total_facts", "first_seen", "last_seen", "types"],
            "properties": {
              "total_facts": {"type": "integer", "minimum": 0},
              "first_seen": {"type": ["string", "null"], "format": "date"},
              "last_seen": {"type": ["string", "null"], "format": "date"},
              "types": {
                "type": "object",
                "description": "Counts keyed by the documented BORME fact_type.",
                "additionalProperties": {"type": "integer", "minimum": 0}
              }
            },
            "additionalProperties": false
          },
          "attribution": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "const": "borme"
          },
          "sync_date": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "PersonDocumentaryReport": {
        "type": "object",
        "description": "Exact person_public_v1 report. It groups unresolved BORME name mentions and never proves identity or current vigency.",
        "required": ["slug", "name", "first_seen", "last_seen", "companies_count", "active_positions", "inactive_positions", "subject_type", "identity_resolution", "positions_semantics", "_legal_notice", "_correction_channel", "schema_version", "status", "projection", "_source_catalog", "_data_sources_used"],
        "properties": {
          "slug": {"type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
          "name": {"type": "string", "minLength": 1},
          "first_seen": {"type": ["string", "null"], "format": "date"},
          "last_seen": {"type": ["string", "null"], "format": "date"},
          "companies_count": {"type": "integer", "minimum": 1},
          "active_positions": {"type": "array", "items": {"$ref": "#/components/schemas/PersonDocumentaryPosition"}},
          "inactive_positions": {"type": "array", "items": {"$ref": "#/components/schemas/PersonDocumentaryPosition"}},
          "subject_type": {"type": "string", "const": "person_documentary_mentions"},
          "identity_resolution": {"type": "string", "const": "not_performed"},
          "positions_semantics": {"type": "string", "minLength": 1},
          "_legal_notice": {"type": "string", "minLength": 1},
          "_correction_channel": {"type": "string", "format": "uri", "const": "https://openmercantil.es/proteccion-de-datos/derechos"},
          "schema_version": {"type": "string", "const": "person_documentary_report_v1"},
          "status": {"type": "string", "const": "available"},
          "projection": {"$ref": "#/components/schemas/PersonPublicProjectionMetadata"},
          "_source_catalog": {"$ref": "#/components/schemas/SourceCatalogEnvelope"},
          "_data_sources_used": {"type": "array", "minItems": 1, "items": {"$ref": "#/components/schemas/PublicSourcePolicyMetadata"}},
          "_attributions": {"type": "object", "additionalProperties": {"type": "string"}}
        },
        "additionalProperties": false
      },
      "SectorCompaniesResponse": {
        "type": "object",
        "required": [
          "code",
          "count",
          "count_status",
          "limit",
          "offset",
          "sort",
          "items"
        ],
        "properties": {
          "code": {
            "type": "string"
          },
          "count": {
            "type": [
              "integer",
              "null"
            ]
          },
          "count_status": {
            "type": "string",
            "enum": [
              "precomputed",
              "not_precomputed"
            ]
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "sort": {
            "type": "string"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CompanySearchItem"
            },
            "maxItems": 100
          }
        },
        "additionalProperties": false
      },
      "RelationshipRecord": {
        "type": "object",
        "description": "Policy-authorized corporate relationship record.",
        "properties": {
          "source_slug": {
            "type": "string"
          },
          "relationship_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "slug": {
            "type": [
              "string",
              "null"
            ]
          },
          "date": {
            "type": [
              "string",
              "null"
            ]
          },
          "official_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "CompanyRelationshipsResponse": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "relationships": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RelationshipRecord"
            }
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RelationshipRecord"
            }
          },
          "source_catalog_version": {
            "type": "string"
          },
          "_source_catalog": {
            "$ref": "#/components/schemas/SourceCatalogEnvelope"
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "SectorRatio": {
        "type": "object",
        "required": [
          "year",
          "metric",
          "value",
          "unit",
          "source"
        ],
        "properties": {
          "year": {
            "type": "integer"
          },
          "metric": {
            "type": "string",
            "enum": ["margen_neto", "roa", "roe"]
          },
          "value": {
            "type": "number"
          },
          "unit": {
            "type": "string",
            "const": "%"
          },
          "source": {
            "type": "string",
            "const": "BdE Central de Balances"
          }
        },
        "additionalProperties": false
      },
      "SectorRatiosResponse": {
        "type": "object",
        "required": [
          "code",
          "ratios"
        ],
        "properties": {
          "code": {
            "type": "string",
            "pattern": "^[0-9]{2}$",
            "minLength": 2,
            "maxLength": 2
          },
          "ratios": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SectorRatio"
            }
          }
        },
        "additionalProperties": false
      },
      "HealthResponse": {
        "type": "object",
        "required": [
          "status",
          "service",
          "version",
          "projection",
          "projection_generation",
          "generated_at",
          "artifacts_age_hours",
          "latest_borme_processed",
          "companies_indexed_approx",
          "total_events_approx",
          "count_source",
          "features",
          "degraded"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "stale",
              "error"
            ]
          },
          "service": {
            "type": "string",
            "const": "openmercantil"
          },
          "version": {
            "type": "string"
          },
          "projection": {
            "type": "string",
            "const": "global_counters_v1"
          },
          "projection_generation": {
            "type": "string",
            "pattern": "^gc1-[a-f0-9]{64}$"
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          },
          "artifacts_age_hours": {
            "type": "number",
            "minimum": 0
          },
          "latest_borme_processed": {
            "type": "string",
            "format": "date"
          },
          "companies_indexed_approx": {
            "type": "integer",
            "minimum": 0
          },
          "total_events_approx": {
            "type": "integer",
            "minimum": 0
          },
          "count_source": {
            "type": "string",
            "const": "offline_projection"
          },
          "features": {
            "type": "object",
            "description": "Runtime feature health. Cheap signals only (env + offline counters); no live query in the request path.",
            "required": [
              "google_signin",
              "sources_catalog",
              "data_fresh"
            ],
            "properties": {
              "google_signin": {
                "type": "string",
                "enum": [
                  "available",
                  "disabled"
                ]
              },
              "sources_catalog": {
                "type": "string",
                "enum": [
                  "valid",
                  "invalid"
                ]
              },
              "data_fresh": {
                "type": "boolean"
              }
            },
            "additionalProperties": false
          },
          "degraded": {
            "type": "boolean",
            "description": "True when any feature is disabled/invalid or the data is stale (artifacts_age_hours >= 26), even if status is still \"ok\"."
          }
        },
        "additionalProperties": false
      },
      "CnaeNode": {
        "type": "object",
        "description": "CNAE node. Catalog loaders may add official explanatory fields.",
        "properties": {
          "code": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "level": {
            "type": [
              "integer",
              "null"
            ]
          },
          "parent": {
            "type": [
              "string",
              "null"
            ]
          },
          "companies_count": {
            "type": [
              "integer",
              "null"
            ]
          },
          "count_status": {
            "type": "string",
            "enum": [
              "precomputed",
              "not_precomputed"
            ]
          },
          "children": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CnaeNode"
            }
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "CnaeTreeResponse": {
        "type": "object",
        "required": [
          "sections"
        ],
        "properties": {
          "sections": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CnaeNode"
            }
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "PersonSearchItem": {
        "type": "object",
        "description": "Documentary person search result; no DNI, contact data or personal address.",
        "required": ["slug", "name", "mentions_count", "companies_count", "first_seen", "last_seen", "subject_type", "identity_resolution", "source_slug"],
        "properties": {
          "slug": {"type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
          "name": {"type": "string", "minLength": 1},
          "mentions_count": {"type": "integer", "minimum": 1},
          "companies_count": {"type": "integer", "minimum": 1},
          "first_seen": {"type": ["string", "null"], "format": "date"},
          "last_seen": {"type": ["string", "null"], "format": "date"},
          "subject_type": {"type": "string", "const": "person_documentary_mentions"},
          "identity_resolution": {"type": "string", "const": "not_performed"},
          "source_slug": {"type": "string", "const": "borme"}
        },
        "additionalProperties": false
      },
      "PersonSearchResponse": {
        "type": "object",
        "required": ["schema_version", "status", "query", "count", "items", "subject_type", "identity_resolution", "projection", "_legal_notice", "_source_catalog", "_data_sources_used"],
        "properties": {
          "schema_version": {"type": "string", "const": "person_search_v1"},
          "status": {"type": "string", "const": "available"},
          "query": {"type": "string", "minLength": 2, "maxLength": 200},
          "count": {"type": "integer", "minimum": 0, "maximum": 50},
          "items": {
            "type": "array",
            "maxItems": 50,
            "items": {
              "$ref": "#/components/schemas/PersonSearchItem"
            }
          },
          "subject_type": {"type": "string", "const": "person_documentary_mentions"},
          "identity_resolution": {"type": "string", "const": "not_performed"},
          "projection": {"$ref": "#/components/schemas/PersonPublicProjectionMetadata"},
          "_legal_notice": {"type": "string", "minLength": 1},
          "_source_catalog": {"$ref": "#/components/schemas/SourceCatalogEnvelope"},
          "_data_sources_used": {"type": "array", "minItems": 1, "items": {"$ref": "#/components/schemas/PublicSourcePolicyMetadata"}},
          "_attributions": {"type": "object", "additionalProperties": {"type": "string"}}
        },
        "additionalProperties": false
      },
      "CompanyLeiResponse": {
        "type": "object",
        "description": "Current GLEIF helper shape. The source-policy gate may make this operation unavailable; has_lei=false is the runtime empty shape, not independent proof of non-registration.",
        "required": [
          "projection_status",
          "projection",
          "slug",
          "has_lei",
          "_source_catalog",
          "_data_sources_used"
        ],
        "properties": {
          "projection_status": {
            "type": "string",
            "const": "available"
          },
          "projection": {
            "type": "string",
            "const": "gleif_lei_v1"
          },
          "slug": {
            "type": "string"
          },
          "has_lei": {
            "type": "boolean"
          },
          "cif": {
            "type": [
              "string",
              "null"
            ]
          },
          "lei": {
            "type": [
              "string",
              "null"
            ]
          },
          "legal_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "legal_form": {
            "type": [
              "string",
              "null"
            ]
          },
          "registration_status": {
            "type": [
              "string",
              "null"
            ]
          },
          "registered_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "legal_form_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": ["string", "null"]
          },
          "validated_as": {
            "type": ["string", "null"]
          },
          "validated_as_is_nif": {
            "type": ["integer", "null"],
            "enum": [0, 1, null]
          },
          "legal_city": {
            "type": ["string", "null"]
          },
          "legal_region": {
            "type": ["string", "null"]
          },
          "legal_postal": {
            "type": ["string", "null"]
          },
          "hq_city": {
            "type": ["string", "null"]
          },
          "hq_region": {
            "type": ["string", "null"]
          },
          "hq_postal": {
            "type": ["string", "null"]
          },
          "successor_lei": {
            "type": ["string", "null"]
          },
          "next_renewal_date": {
            "type": ["string", "null"]
          },
          "jurisdiction": {
            "type": ["string", "null"]
          },
          "category": {
            "type": ["string", "null"]
          },
          "creation_date": {
            "type": ["string", "null"]
          },
          "registered_at_id": {
            "type": ["string", "null"]
          },
          "managing_lou": {
            "type": ["string", "null"]
          },
          "hq_differs": {
            "type": "boolean"
          },
          "_source_catalog": {
            "$ref": "#/components/schemas/SourceCatalogEnvelope"
          },
          "_data_sources_used": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicSourcePolicyMetadata"
            }
          },
          "_attributions": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        },
        "additionalProperties": false
      },
      "BdeSectorMetric": {
        "type": "object",
        "required": [
          "value",
          "unit",
          "year",
          "source"
        ],
        "properties": {
          "value": {
            "type": "number"
          },
          "unit": {
            "type": "string"
          },
          "year": {
            "type": "integer"
          },
          "source": {
            "type": "string",
            "const": "bde"
          }
        },
        "additionalProperties": false
      },
      "CompanyBdeResponse": {
        "type": "object",
        "description": "Banco de Espana Central de Balances ratios for the company's two-digit CNAE sector. These are sector metrics, not a supervised-entity record or company score.",
        "required": [
          "projection_status",
          "projection",
          "slug",
          "is_alias",
          "identity_generation",
          "projection_generation",
          "projected_at",
          "source_catalog_version",
          "coverage_status",
          "has_data",
          "metrics",
          "_source_catalog",
          "_data_sources_used"
        ],
        "properties": {
          "projection_status": {
            "type": "string",
            "const": "available"
          },
          "projection": {
            "type": "string",
            "const": "bde_sector_ratios_v1"
          },
          "slug": {
            "type": "string"
          },
          "is_alias": {
            "type": "boolean"
          },
          "identity_generation": {
            "type": "string",
            "pattern": "^cpv2-[a-f0-9]{64}$"
          },
          "projection_generation": {
            "type": "string",
            "pattern": "^sr1-[a-f0-9]{64}$"
          },
          "projected_at": {
            "type": "string",
            "format": "date-time"
          },
          "source_catalog_version": {
            "type": "string",
            "minLength": 1
          },
          "coverage_status": {
            "type": "string",
            "enum": ["matched", "sector_not_projected", "cnae_unavailable"]
          },
          "has_data": {
            "type": "boolean"
          },
          "cnae_code": {
            "type": "string"
          },
          "sector_code": {
            "type": "string",
            "pattern": "^[0-9]{2}$"
          },
          "metrics": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/BdeSectorMetric"
            }
          },
          "_source_catalog": {
            "$ref": "#/components/schemas/SourceCatalogEnvelope"
          },
          "_data_sources_used": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicSourcePolicyMetadata"
            }
          },
          "_attributions": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        },
        "additionalProperties": false
      },
      "CnmvListingRecord": {
        "type": "object",
        "required": ["ticker", "isin", "market"],
        "properties": {
          "ticker": {"type": "string", "minLength": 1, "maxLength": 20},
          "isin": {"type": "string", "minLength": 12, "maxLength": 12},
          "market": {"type": "string", "minLength": 1, "maxLength": 80}
        },
        "additionalProperties": false
      },
      "CnmvEventRecord": {
        "type": "object",
        "required": ["date", "type", "title", "notice_url"],
        "properties": {
          "date": {"type": "string", "format": "date"},
          "type": {"type": "string", "minLength": 1, "maxLength": 120},
          "title": {"type": "string", "minLength": 1, "maxLength": 500},
          "notice_url": {"type": "string", "format": "uri", "pattern": "^https://(?:[^/]+\\.)?cnmv\\.es/"}
        },
        "additionalProperties": false
      },
      "CompanyCnmvResponse": {
        "type": "object",
        "description": "Generation-bound minimized CNMV view. A null listing or empty events array describes this bounded projection only.",
        "required": ["projection_status", "projection", "slug", "cif", "complete_bounded_projection", "coverage_status", "source_metadata", "coverage_notice", "listing", "events_total", "returned_events_count", "events", "documentary_notice", "_source_catalog", "_data_sources_used"],
        "properties": {
          "projection_status": {"type": "string", "const": "available"},
          "projection": {"$ref": "#/components/schemas/CompanyIntegrationProjection"},
          "slug": {"type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
          "cif": {"type": "string", "pattern": "^[ABCDEFGHJNPQRSUVW][0-9]{7}[0-9A-J]$"},
          "complete_bounded_projection": {"type": "boolean", "const": true},
          "coverage_status": {"type": "string", "enum": ["available", "empty"]},
          "source_metadata": {"$ref": "#/components/schemas/CompanyIntegrationSourceMetadata"},
          "coverage_notice": {"type": "string"},
          "listing": {"anyOf": [{"$ref": "#/components/schemas/CnmvListingRecord"}, {"type": "null"}]},
          "events_total": {"type": "integer", "minimum": 0, "maximum": 20},
          "returned_events_count": {"type": "integer", "minimum": 0, "maximum": 20},
          "events": {"type": "array", "maxItems": 20, "items": {"$ref": "#/components/schemas/CnmvEventRecord"}},
          "documentary_notice": {"type": "string"},
          "_source_catalog": {"$ref": "#/components/schemas/SourceCatalogEnvelope"},
          "_data_sources_used": {"type": "array", "items": {"$ref": "#/components/schemas/PublicSourcePolicyMetadata"}},
          "_attributions": {"type": "object", "additionalProperties": {"type": "string"}}
        },
        "additionalProperties": false
      },
      "CompanyAeatDebtorResponse": {
        "type": "object",
        "required": [
          "slug",
          "listed"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "cif": {
            "type": [
              "string",
              "null"
            ]
          },
          "listed": {
            "type": "boolean"
          },
          "debt_eur": {
            "type": [
              "number",
              "null"
            ]
          },
          "period": {
            "type": [
              "string",
              "null"
            ]
          },
          "published_date": {
            "type": [
              "string",
              "null"
            ]
          },
          "history": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/JsonValue"
            }
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "WikidataCompanyRecord": {
        "type": "object",
        "description": "Structured CC0 subset only; no label, logo, website, CEO, LEI, Wikipedia text or media.",
        "required": ["qid", "entity_url", "ticker", "inception"],
        "properties": {
          "qid": {"type": "string", "pattern": "^Q[1-9][0-9]*$"},
          "entity_url": {"type": "string", "format": "uri", "pattern": "^https://www\\.wikidata\\.org/entity/Q[1-9][0-9]*$"},
          "ticker": {"type": ["string", "null"]},
          "inception": {"type": ["string", "null"], "format": "date"}
        },
        "additionalProperties": false
      },
      "CompanyWikidataResponse": {
        "type": "object",
        "description": "Generation-bound minimized Wikidata company view. Empty describes the bounded projection only.",
        "required": ["projection_status", "projection", "slug", "cif", "complete_bounded_projection", "coverage_status", "source_metadata", "coverage_notice", "count", "item", "_source_catalog", "_data_sources_used"],
        "properties": {
          "projection_status": {"type": "string", "const": "available"},
          "projection": {"$ref": "#/components/schemas/CompanyIntegrationProjection"},
          "slug": {"type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
          "cif": {"type": "string", "pattern": "^[ABCDEFGHJNPQRSUVW][0-9]{7}[0-9A-J]$"},
          "complete_bounded_projection": {"type": "boolean", "const": true},
          "coverage_status": {"type": "string", "enum": ["available", "empty"]},
          "source_metadata": {"$ref": "#/components/schemas/CompanyIntegrationSourceMetadata"},
          "coverage_notice": {"type": "string"},
          "count": {"type": "integer", "minimum": 0, "maximum": 1},
          "item": {"anyOf": [{"$ref": "#/components/schemas/WikidataCompanyRecord"}, {"type": "null"}]},
          "_source_catalog": {"$ref": "#/components/schemas/SourceCatalogEnvelope"},
          "_data_sources_used": {"type": "array", "items": {"$ref": "#/components/schemas/PublicSourcePolicyMetadata"}},
          "_attributions": {"type": "object", "additionalProperties": {"type": "string"}}
        },
        "additionalProperties": false
      },
      "TedContractRecord": {
        "type": "object",
        "description": "Minimized, attested TED notice. Tenderer, currency and connector free text are excluded.",
        "required": ["publication_number", "publication_date", "buyer_name", "notice_url"],
        "properties": {
          "publication_number": {"type": "string", "minLength": 1, "maxLength": 100},
          "publication_date": {"type": "string", "format": "date"},
          "buyer_name": {"type": "string", "minLength": 1, "maxLength": 300},
          "notice_url": {"type": "string", "format": "uri", "pattern": "^https://(?:[^/]+\\.)?ted\\.europa\\.eu/"}
        },
        "additionalProperties": false
      },
      "CompanyTedResponse": {
        "type": "object",
        "description": "Generation-bound minimized TED view. count is the total projected row count; returned_count is the bounded slice length.",
        "required": ["projection_status", "projection", "slug", "cif", "complete_bounded_projection", "coverage_status", "source_metadata", "coverage_notice", "count", "returned_count", "items", "documentary_notice", "_source_catalog", "_data_sources_used"],
        "properties": {
          "projection_status": {"type": "string", "const": "available"},
          "projection": {"$ref": "#/components/schemas/CompanyIntegrationProjection"},
          "slug": {"type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
          "cif": {"type": "string", "pattern": "^[ABCDEFGHJNPQRSUVW][0-9]{7}[0-9A-J]$"},
          "complete_bounded_projection": {"type": "boolean", "const": true},
          "coverage_status": {"type": "string", "enum": ["available", "empty"]},
          "source_metadata": {"$ref": "#/components/schemas/CompanyIntegrationSourceMetadata"},
          "coverage_notice": {"type": "string"},
          "count": {"type": "integer", "minimum": 0, "maximum": 100},
          "returned_count": {"type": "integer", "minimum": 0, "maximum": 100},
          "items": {"type": "array", "maxItems": 100, "items": {"$ref": "#/components/schemas/TedContractRecord"}},
          "documentary_notice": {"type": "string"},
          "_source_catalog": {"$ref": "#/components/schemas/SourceCatalogEnvelope"},
          "_data_sources_used": {"type": "array", "items": {"$ref": "#/components/schemas/PublicSourcePolicyMetadata"}},
          "_attributions": {"type": "object", "additionalProperties": {"type": "string"}}
        },
        "additionalProperties": false
      },
      "CompanyAccountsResponse": {
        "type": "object",
        "description": "Current annual-accounts aggregate helper response. The operation remains source-policy gated; al_dia and has_financials are runtime aggregate flags, not registry certificates.",
        "required": [
          "projection_status",
          "projection",
          "slug",
          "cif",
          "count",
          "al_dia",
          "last_year",
          "last_deposit_date",
          "has_financials",
          "years",
          "_source_catalog",
          "_data_sources_used"
        ],
        "properties": {
          "projection_status": {
            "type": "string",
            "const": "available"
          },
          "projection": {
            "type": "string",
            "const": "annual_accounts_v1"
          },
          "slug": {
            "type": "string"
          },
          "cif": {
            "type": ["string", "null"]
          },
          "count": {
            "type": "integer",
            "minimum": 0
          },
          "al_dia": {
            "type": "boolean"
          },
          "last_year": {
            "type": ["integer", "null"]
          },
          "last_deposit_date": {
            "type": ["string", "null"]
          },
          "has_financials": {
            "type": "boolean"
          },
          "years": {
            "oneOf": [
              {
                "type": "object",
                "propertyNames": {
                  "pattern": "^-?[0-9]+$"
                },
                "additionalProperties": {
                  "$ref": "#/components/schemas/FinancialAccountsRecord"
                }
              },
              {
                "type": "array",
                "maxItems": 0
              }
            ]
          },
          "_source_catalog": {
            "$ref": "#/components/schemas/SourceCatalogEnvelope"
          },
          "_data_sources_used": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicSourcePolicyMetadata"
            }
          },
          "_attributions": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        },
        "additionalProperties": false
      },
      "FinancialAccountsRecord": {
        "type": "object",
        "description": "Source-precedence annual-accounts row emitted under a year key. Monetary values are integer euros derived from stored cents; no accounting concept is inferred.",
        "required": [
          "source",
          "deposit_date",
          "status",
          "ingresos_eur",
          "beneficio_eur",
          "activo_eur",
          "patrimonio_eur",
          "pdf_url"
        ],
        "properties": {
          "source": {
            "type": [
              "string",
              "null"
            ]
          },
          "deposit_date": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": [
              "string",
              "null"
            ]
          },
          "ingresos_eur": {
            "type": [
              "integer",
              "null"
            ]
          },
          "beneficio_eur": {
            "type": [
              "integer",
              "null"
            ]
          },
          "activo_eur": {
            "type": [
              "integer",
              "null"
            ]
          },
          "patrimonio_eur": {
            "type": ["integer", "null"]
          },
          "pdf_url": {
            "type": ["string", "null"]
          }
        },
        "additionalProperties": false
      },
      "CompanyActivityResponse": {
        "type": "object",
        "required": [
          "slug",
          "count",
          "series"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "series": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "period": {
                  "type": "string"
                },
                "count": {
                  "type": "integer"
                }
              },
              "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
            }
          }
        },
        "additionalProperties": false
      },
      "CompanyActivityScoreResponse": {
        "type": "object",
        "required": [
          "slug",
          "score",
          "breakdown"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "score": {
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "breakdown": {
            "type": "object",
            "additionalProperties": {
              "type": "object",
              "required": ["value", "max", "desc"],
              "properties": {
                "value": {"type": "number"},
                "max": {"type": "number"},
                "desc": {"type": "string"}
              },
              "additionalProperties": false
            }
          },
          "methodology": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "CompanySimilarResponse": {
        "type": "object",
        "required": [
          "slug",
          "count",
          "items"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CompanySearchItem"
            },
            "maxItems": 20
          }
        },
        "additionalProperties": false
      },
      "EmbargoRecord": {
        "type": "object",
        "description": "Documentary official-notice record; may not reflect later unpublished resolutions.",
        "properties": {
          "date": {
            "type": [
              "string",
              "null"
            ]
          },
          "authority": {
            "type": [
              "string",
              "null"
            ]
          },
          "summary": {
            "type": [
              "string",
              "null"
            ]
          },
          "amount_eur": {
            "type": [
              "number",
              "null"
            ]
          },
          "source_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "CompanyEmbargoesResponse": {
        "type": "object",
        "required": [
          "slug",
          "count",
          "items",
          "source",
          "note"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "summary": {
            "anyOf": [
              {"type": "object", "properties": {"count": {"type": "integer"}, "total_amount_eur": {"type": ["number", "null"]}, "latest_date": {"type": ["string", "null"]}}, "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}},
              {"type": "null"}
            ]
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmbargoRecord"
            },
            "maxItems": 100
          },
          "source": {
            "type": "string"
          },
          "note": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "CompanyEnrichmentResponse": {
        "type": "object",
        "description": "Policy-filtered enrichment envelope. Only public catalog sources survive egress filtering.",
        "properties": {
          "slug": {
            "type": "string"
          },
          "sources": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/JsonValue"
            }
          },
          "_source_catalog": {
            "$ref": "#/components/schemas/SourceCatalogEnvelope"
          },
          "_data_sources_used": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicSourcePolicyMetadata"
            }
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "JsonValue": {
        "description": "A JSON value used only inside explicitly documented extension maps.",
        "oneOf": [
          {
            "type": [
              "string",
              "number",
              "boolean",
              "null"
            ]
          },
          {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/JsonValue"
            }
          },
          {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/JsonValue"
            }
          }
        ]
      },
      "OfflineProjectionError": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "projection": {
            "type": [
              "string",
              "null"
            ]
          },
          "derivation": {
            "type": [
              "string",
              "null"
            ]
          },
          "detail": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "additionalProperties": false
      },
      "TenderCoverage": {
        "type": "object",
        "properties": {
          "projection": {
            "type": [
              "string",
              "null"
            ]
          },
          "lots": {
            "type": [
              "string",
              "null"
            ]
          },
          "multiple_cpv": {
            "type": [
              "string",
              "null"
            ]
          },
          "supplier_edges": {
            "type": [
              "string",
              "null"
            ]
          },
          "documents": {
            "type": [
              "string",
              "null"
            ]
          },
          "cpv_prefix_filter": {
            "type": [
              "string",
              "null"
            ],
            "description": "Indexed offline 2-8 digit prefix coverage; undated projection rows are excluded."
          },
          "projection_generation": {
            "type": "string",
            "pattern": "^placsp12-[a-f0-9]{64}$",
            "description": "Immutable PLACSP projection generation used for this response."
          },
          "company_public_generation": {
            "type": "string",
            "pattern": "^cpv2-[a-f0-9]{64}$",
            "description": "Immutable company_public_v2 generation that revalidated the requested company identity."
          }
        },
        "additionalProperties": false
      },
      "TenderCollectionMetadata": {
        "type": "object",
        "description": "Hard response bounds and per-collection truncation flags. Truncation never triggers an unbounded fallback.",
        "required": ["limits", "truncated"],
        "properties": {
          "limits": {
            "type": "object",
            "required": ["lots", "cpv_codes", "suppliers", "results"],
            "properties": {
              "lots": {"type": "integer", "const": 100},
              "cpv_codes": {"type": "integer", "const": 500},
              "suppliers": {"type": "integer", "const": 250},
              "results": {"type": "integer", "const": 100}
            },
            "additionalProperties": false
          },
          "truncated": {
            "type": "object",
            "required": ["lots", "cpv_codes", "suppliers", "results"],
            "properties": {
              "lots": {"type": "boolean"},
              "cpv_codes": {"type": "boolean"},
              "suppliers": {"type": "boolean"},
              "results": {"type": "boolean"}
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": false
      },
      "TenderSearchFilters": {
        "type": "object",
        "required": ["q", "cpv", "phase", "buyer_nif", "supplier_cif", "province", "published_from", "published_to", "amount_kind", "min_amount_eur", "max_amount_eur", "open_only"],
        "properties": {
          "q": {
            "type": [
              "string",
              "null"
            ]
          },
          "cpv": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^[0-9]{2,8}$"
          },
          "phase": {
            "type": [
              "string",
              "null"
            ]
          },
          "buyer_nif": {
            "type": [
              "string",
              "null"
            ]
          },
          "supplier_cif": {
            "type": [
              "string",
              "null"
            ]
          },
          "province": {
            "type": [
              "string",
              "null"
            ]
          },
          "published_from": {
            "type": [
              "string",
              "null"
            ]
          },
          "published_to": {
            "type": [
              "string",
              "null"
            ]
          },
          "amount_kind": {
            "type": [
              "string",
              "null"
            ]
          },
          "min_amount_eur": {
            "type": [
              "number",
              "null"
            ]
          },
          "max_amount_eur": {
            "type": [
              "number",
              "null"
            ]
          },
          "open_only": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "TenderGeography": {
        "type": "object",
        "required": [
          "matched_records",
          "coverage_percent",
          "warning"
        ],
        "properties": {
          "matched_records": {
            "type": "integer"
          },
          "coverage_percent": {
            "type": "number"
          },
          "warning": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "TenderDataQuality": {
        "type": "object",
        "required": ["v3_records", "multi_lot_records", "multi_cpv_records", "multi_supplier_records", "withheld_supplier_records", "amount_semantics"],
        "properties": {
          "v3_records": {
            "type": "integer"
          },
          "multi_lot_records": {
            "type": "integer"
          },
          "multi_cpv_records": {
            "type": "integer"
          },
          "multi_supplier_records": {
            "type": "integer"
          },
          "withheld_supplier_records": {
            "type": "integer"
          },
          "amount_semantics": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "PublicIntegrationCoverage": {
        "type": "object",
        "properties": {
          "multi_lot": {
            "type": [
              "string",
              "null"
            ]
          },
          "multiple_cpv": {
            "type": [
              "string",
              "null"
            ]
          },
          "geography": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "additionalProperties": false
      },
      "PublicIntegrationContract": {
        "type": "object",
        "required": [
          "surface",
          "secrets_exposed",
          "writes_exposed"
        ],
        "properties": {
          "surface": {
            "type": "string",
            "const": "public-read-only"
          },
          "secrets_exposed": {
            "type": "boolean",
            "const": false
          },
          "writes_exposed": {
            "type": "boolean",
            "const": false
          },
          "health_semantics": {
            "type": [
              "string",
              "null"
            ]
          },
          "excluded": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": false
      },
      "OkResponse": {
        "type": "object",
        "required": [
          "ok"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "DeletedResponse": {
        "type": "object",
        "required": [
          "ok",
          "deleted"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "deleted": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "CredentialRevokedResponse": {
        "type": "object",
        "required": [
          "ok",
          "revoked"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "revoked": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "EmailDispatchResponse": {
        "type": "object",
        "required": [
          "ok",
          "email_sent"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "email_sent": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "VerificationDispatchResponse": {
        "type": "object",
        "required": [
          "ok",
          "sent"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "sent": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "UserMeResponse": {
        "type": "object",
        "required": [
          "id",
          "plan",
          "onboarded",
          "csrf"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "format": "email"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "plan": {
            "type": "string"
          },
          "persona_primary": {
            "type": [
              "string",
              "null"
            ]
          },
          "onboarded": {
            "type": "integer"
          },
          "csrf": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "OrganizationMember": {
        "type": "object",
        "required": [
          "id",
          "name",
          "email",
          "role"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "owner",
              "admin",
              "member"
            ]
          }
        },
        "additionalProperties": false
      },
      "OrganizationInvite": {
        "type": "object",
        "required": [
          "id",
          "email",
          "role",
          "created_at",
          "expires_at"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "role": {
            "type": "string"
          },
          "created_at": {
            "type": "string"
          },
          "expires_at": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "UserOrganizationResponse": {
        "type": "object",
        "properties": {
          "org": {
            "anyOf": [
              {
                "type": "object",
                "required": [
                  "id",
                  "name",
                  "my_role"
                ],
                "properties": {
                  "id": {
                    "type": "integer"
                  },
                  "name": {
                    "type": "string"
                  },
                  "my_role": {
                    "type": "string"
                  }
                },
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ]
          },
          "can_team": {
            "type": "boolean"
          },
          "seats": {
            "type": "object",
            "required": [
              "used",
              "max"
            ],
            "properties": {
              "used": {
                "type": "integer"
              },
              "max": {
                "type": "integer"
              }
            },
            "additionalProperties": false
          },
          "members": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrganizationMember"
            }
          },
          "invites": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrganizationInvite"
            }
          }
        },
        "additionalProperties": false
      },
      "OrganizationCreatedResponse": {
        "type": "object",
        "required": [
          "ok",
          "org_id"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "org_id": {
            "type": "integer"
          }
        },
        "additionalProperties": false
      },
      "OrganizationInviteCreatedResponse": {
        "type": "object",
        "required": [
          "ok",
          "invite_id",
          "email",
          "role",
          "expires_at",
          "renewed",
          "email_sent"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "invite_id": {
            "type": "integer"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "role": {
            "type": "string"
          },
          "expires_at": {
            "type": "string"
          },
          "renewed": {
            "type": "boolean"
          },
          "email_sent": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "PersonaOption": {
        "type": "object",
        "required": [
          "slug",
          "name",
          "tagline",
          "icon"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "tagline": {
            "type": "string"
          },
          "icon": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "additionalProperties": false
      },
      "UserPersonaResponse": {
        "type": "object",
        "required": [
          "persona_primary",
          "persona",
          "available"
        ],
        "properties": {
          "persona_primary": {
            "type": [
              "string",
              "null"
            ]
          },
          "persona": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "slug": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "tagline": {
                    "type": "string"
                  }
                },
                "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
              },
              {
                "type": "null"
              }
            ]
          },
          "available": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PersonaOption"
            }
          }
        },
        "additionalProperties": false
      },
      "UserPersonaSelectedResponse": {
        "type": "object",
        "required": [
          "ok",
          "persona"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "persona": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "UserSegment": {
        "type": "object",
        "description": "Saved account segment. Extra migration columns may be returned for backward compatibility.",
        "properties": {
          "id": {
            "type": "integer"
          },
          "user_id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "filters_json": {
            "type": "string"
          },
          "filters": {
            "$ref": "#/components/schemas/UserSegmentStoredFilters"
          },
          "persona": {
            "type": [
              "string",
              "null"
            ]
          },
          "icon": {
            "type": [
              "string",
              "null"
            ]
          },
          "pinned": {
            "type": [
              "integer",
              "boolean"
            ]
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "UserSegmentListResponse": {
        "type": "object",
        "required": [
          "count",
          "tier_max",
          "segments"
        ],
        "properties": {
          "count": {
            "type": "integer"
          },
          "tier_max": {
            "type": "integer"
          },
          "segments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserSegment"
            },
            "maxItems": 500
          }
        },
        "additionalProperties": false
      },
      "UserSegmentCreatedResponse": {
        "type": "object",
        "required": [
          "id",
          "segment"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "segment": {
            "$ref": "#/components/schemas/UserSegment"
          }
        },
        "additionalProperties": false
      },
      "UserSegmentPinResponse": {
        "type": "object",
        "required": [
          "pinned"
        ],
        "properties": {
          "pinned": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "UserSegmentRunResponse": {
        "type": "object",
        "required": [
          "segment_id",
          "count",
          "rows",
          "filters_applied"
        ],
        "properties": {
          "segment_id": {
            "type": "integer"
          },
          "count": {
            "type": "integer",
            "minimum": 0,
            "maximum": 500,
            "description": "Number of rows returned in this bounded response. It is not an exact global match count."
          },
          "rows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CompanySearchItem"
            },
            "maxItems": 500
          },
          "filters_applied": {
            "$ref": "#/components/schemas/UserSegmentFilters"
          }
        },
        "additionalProperties": false
      },
      "UserListItem": {
        "type": "object",
        "description": "Saved list item owned by the authenticated account.",
        "properties": {
          "id": {
            "type": "integer"
          },
          "list_id": {
            "type": "integer"
          },
          "item_type": {
            "type": "string"
          },
          "item_slug": {
            "type": "string"
          },
          "note": {
            "type": "string"
          },
          "added_at": {
            "type": "string"
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "UserList": {
        "type": "object",
        "description": "Saved user list; migration columns may be appended.",
        "properties": {
          "id": {
            "type": "integer"
          },
          "user_id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "color": {
            "type": [
              "string",
              "null"
            ]
          },
          "kind": {
            "type": "string",
            "enum": [
              "company",
              "person",
              "mixed"
            ]
          },
          "item_count": {
            "type": "integer"
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "UserListDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/UserList"
          },
          {
            "type": "object",
            "required": [
              "items"
            ],
            "properties": {
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/UserListItem"
                },
                "maxItems": 1000
              }
            },
            "additionalProperties": false
          }
        ]
      },
      "UserListListResponse": {
        "type": "object",
        "required": [
          "count",
          "tier_max",
          "lists"
        ],
        "properties": {
          "count": {
            "type": "integer"
          },
          "tier_max": {
            "type": "integer"
          },
          "lists": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserList"
            }
          }
        },
        "additionalProperties": false
      },
      "UserListCreatedResponse": {
        "type": "object",
        "required": [
          "id",
          "list"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "list": {
            "$ref": "#/components/schemas/UserList"
          }
        },
        "additionalProperties": false
      },
      "UserNote": {
        "type": "object",
        "description": "Private note visible only to its authenticated owner.",
        "properties": {
          "id": {
            "type": "integer"
          },
          "user_id": {
            "type": "integer"
          },
          "target_type": {
            "type": "string"
          },
          "target_id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "pinned": {
            "type": [
              "integer",
              "boolean"
            ]
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "UserNoteListResponse": {
        "type": "object",
        "required": [
          "count",
          "recent"
        ],
        "properties": {
          "count": {
            "type": "integer"
          },
          "recent": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserNote"
            },
            "maxItems": 500
          }
        },
        "additionalProperties": false
      },
      "UserNotesForTargetResponse": {
        "type": "object",
        "required": [
          "count",
          "notes"
        ],
        "properties": {
          "count": {
            "type": "integer"
          },
          "notes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserNote"
            },
            "maxItems": 500
          }
        },
        "additionalProperties": false
      },
      "UserNoteCreatedResponse": {
        "type": "object",
        "required": [
          "id",
          "note"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "note": {
            "$ref": "#/components/schemas/UserNote"
          }
        },
        "additionalProperties": false
      },
      "UserTag": {
        "type": "object",
        "description": "Private account tag and optional aggregate usage count.",
        "properties": {
          "id": {
            "type": "integer"
          },
          "user_id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "color": {
            "type": [
              "string",
              "null"
            ]
          },
          "usage_count": {
            "type": "integer"
          },
          "created_at": {
            "type": "string"
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "UserTagListResponse": {
        "type": "object",
        "required": [
          "count",
          "tier_max",
          "tags"
        ],
        "properties": {
          "count": {
            "type": "integer"
          },
          "tier_max": {
            "type": "integer"
          },
          "tags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserTag"
            }
          }
        },
        "additionalProperties": false
      },
      "UserTagCreatedResponse": {
        "type": "object",
        "required": [
          "id",
          "tag"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "tag": {
            "$ref": "#/components/schemas/UserTag"
          }
        },
        "additionalProperties": false
      },
      "ExportUsageResponse": {
        "type": "object",
        "required": [
          "used",
          "max",
          "remaining",
          "pct",
          "unlimited"
        ],
        "properties": {
          "used": {
            "type": "integer"
          },
          "max": {
            "type": "integer"
          },
          "remaining": {
            "type": "integer"
          },
          "pct": {
            "type": "integer"
          },
          "unlimited": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "UserExportRecord": {
        "type": "object",
        "description": "Authenticated user's export history metadata.",
        "properties": {
          "id": {
            "type": "integer"
          },
          "type": {
            "type": [
              "string",
              "null"
            ]
          },
          "format": {
            "type": [
              "string",
              "null"
            ]
          },
          "rows_count": {
            "type": "integer"
          },
          "created_at": {
            "type": "string"
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "UserExportListResponse": {
        "type": "object",
        "required": [
          "recent",
          "usage"
        ],
        "properties": {
          "recent": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserExportRecord"
            },
            "maxItems": 500
          },
          "usage": {
            "$ref": "#/components/schemas/ExportUsageResponse"
          }
        },
        "additionalProperties": false
      },
      "UserAuditEntry": {
        "type": "object",
        "description": "Account audit entry. Sensitive metadata is not part of the public contract.",
        "properties": {
          "id": {
            "type": "integer"
          },
          "action": {
            "type": "string"
          },
          "target_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "target_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string"
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "UserAuditResponse": {
        "type": "object",
        "required": [
          "count",
          "entries"
        ],
        "properties": {
          "count": {
            "type": "integer"
          },
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserAuditEntry"
            },
            "maxItems": 1000
          }
        },
        "additionalProperties": false
      },
      "KycUsage": {
        "type": "object",
        "required": [
          "used",
          "max",
          "remaining",
          "window_days",
          "unlimited"
        ],
        "properties": {
          "used": {
            "type": "integer"
          },
          "max": {
            "type": "integer"
          },
          "remaining": {
            "type": "integer"
          },
          "window_days": {
            "type": "integer"
          },
          "unlimited": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "KycPersonLookupResults": {
        "type": "object",
        "required": [
          "aeat_morosos",
          "claims_evidence",
          "borme_facts"
        ],
        "properties": {
          "aeat_morosos": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/JsonValue"
            },
            "maxItems": 10
          },
          "claims_evidence": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/JsonValue"
            },
            "maxItems": 10
          },
          "borme_facts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/JsonValue"
            },
            "maxItems": 20
          }
        },
        "additionalProperties": false
      },
      "KycPersonLookupResponse": {
        "type": "object",
        "required": [
          "ok",
          "status",
          "request_id"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "status": {
            "type": "string"
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "query_redacted": {
            "type": [
              "string",
              "null"
            ]
          },
          "query_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "matches_count": {
            "type": "integer"
          },
          "sources_matched": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "results": {
            "$ref": "#/components/schemas/KycPersonLookupResults"
          },
          "finalidad": {
            "type": [
              "string",
              "null"
            ]
          },
          "usage": {
            "$ref": "#/components/schemas/KycUsage"
          },
          "credits_charged": {
            "type": "integer"
          },
          "request_id": {
            "type": "string"
          },
          "disclaimer": {
            "type": [
              "string",
              "null"
            ]
          },
          "correction_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "audit_url": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "additionalProperties": false
      },
      "KycPersonLookupUsageResponse": {
        "type": "object",
        "required": [
          "tier_allowed"
        ],
        "properties": {
          "tier_allowed": {
            "type": "boolean"
          },
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "upgrade_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "usage": {
            "$ref": "#/components/schemas/KycUsage"
          },
          "disclaimer": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "additionalProperties": false
      },
      "KycLookupHistoryEntry": {
        "type": "object",
        "required": [
          "id",
          "query_type",
          "query_redacted",
          "results_count",
          "sources_matched",
          "status",
          "request_id",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "query_type": {
            "type": "string"
          },
          "query_redacted": {
            "type": "string"
          },
          "results_count": {
            "type": "integer"
          },
          "sources_matched": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "finalidad": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "request_id": {
            "type": "string"
          },
          "created_at": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "KycPersonLookupHistoryResponse": {
        "type": "object",
        "required": [
          "count",
          "total",
          "entries",
          "disclaimer"
        ],
        "properties": {
          "count": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/KycLookupHistoryEntry"
            },
            "maxItems": 200
          },
          "disclaimer": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "WebhookUpdatedResponse": {
        "type": "object",
        "required": [
          "ok",
          "webhook"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "webhook": {
            "$ref": "#/components/schemas/OutboundWebhook"
          }
        },
        "additionalProperties": false
      },
      "SupportTicketCategory": {
        "type": "string",
        "description": "Stable support-routing category accepted by the current account schema.",
        "enum": ["comercial", "tecnico", "datos", "rgpd", "partnerships", "sugerencia", "bug", "otro"]
      },
      "SupportTicketCreateRequest": {
        "type": "object",
        "description": "Customer-supplied support content. Privacy consent is purpose-bound to handling and protecting this request; it is not marketing consent.",
        "required": ["email", "category", "subject", "body", "accept_privacy"],
        "properties": {
          "email": {"type": "string", "format": "email", "maxLength": 254},
          "name": {"type": "string", "maxLength": 200, "pattern": "^[^\\u0000-\\u001F\\u007F]*$", "description": "Trimmed before persistence; ASCII control characters are rejected."},
          "category": {"$ref": "#/components/schemas/SupportTicketCategory"},
          "subject": {"type": "string", "minLength": 6, "maxLength": 200, "pattern": "^[^\\u0000-\\u001F\\u007F]+$", "description": "Trimmed before length validation; ASCII control characters are rejected."},
          "body": {"type": "string", "minLength": 20, "maxLength": 10000, "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$", "description": "Trimmed before length validation. TAB, CR and LF are permitted; other ASCII control characters are rejected."},
          "related_company_slug": {"type": "string", "maxLength": 200, "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$", "description": "Optional validated context; it does not establish identity or ownership."},
          "related_url": {"type": "string", "maxLength": 2048, "description": "Optional context restricted at runtime to a single-slash absolute same-origin path or an HTTPS URL on exactly openmercantil.es, without userinfo, port, backslash or control characters. Query and fragment are removed before persistence. The URL is stored as text and never dereferenced."},
          "accept_privacy": {"type": "boolean", "const": true, "description": "Strict purpose-bound acceptance, persisted as privacy_accepted/privacy_policy_v1; never interpreted as marketing consent."}
        },
        "additionalProperties": false
      },
      "SupportTicketCreatedResponse": {
        "type": "object",
        "required": ["ok", "ticket_id", "public_id"],
        "properties": {
          "ok": {"type": "boolean", "const": true},
          "ticket_id": {"type": "integer", "minimum": 1},
          "public_id": {"type": "string", "pattern": "^OB-[0-9]{4}-[0-9]{6,}$"}
        },
        "additionalProperties": false
      },
      "SupportReplyRequest": {
        "type": "object",
        "required": ["body"],
        "properties": {
          "body": {"type": "string", "minLength": 5, "maxLength": 10000, "description": "Trimmed before the 5–10,000 character validation."}
        },
        "additionalProperties": false
      },
      "SupportErrorResponse": {
        "type": "object",
        "required": ["ok", "error"],
        "properties": {
          "ok": {"type": "boolean", "const": false},
          "error": {"type": "string"},
          "code": {"type": "integer", "description": "Present on selected fail-closed or anti-abuse helper failures."},
          "retry_after": {"type": "integer", "minimum": 1, "description": "Present when the per-IP support creation ceiling is exhausted."}
        },
        "additionalProperties": false
      },
      "SupportRequestErrorResponse": {
        "description": "Support validation/ownership errors carry `ok=false`; shared body-reader and action-budget errors use the generic API error envelope.",
        "anyOf": [
          {"$ref": "#/components/schemas/SupportErrorResponse"},
          {"$ref": "#/components/schemas/ErrorResponse"}
        ]
      },
      "RequestBodyTooLargeError": {
        "type": "object",
        "required": ["error", "max_bytes"],
        "properties": {
          "error": {"type": "string", "const": "request_body_too_large"},
          "max_bytes": {"type": "integer", "minimum": 1}
        },
        "additionalProperties": false
      },
      "LegalReportRequest": {
        "type": "object",
        "description": "The body carries only the CSRF fallback. Entitlement, pricing, beta status and the daily idempotency key are server-owned.",
        "properties": {
          "csrf": {"type": "string", "minLength": 32, "maxLength": 256, "description": "Body fallback; prefer X-CSRF-Token."}
        },
        "additionalProperties": false
      },
      "LegalReportAxis": {
        "type": "object",
        "description": "One documentary axis in the redacted corporate legal-history projection. Presence records sourced events; it does not assert wrongdoing, solvency, current status or identity beyond the corporate subject guard.",
        "required": ["axis_id", "label", "present", "count"],
        "properties": {
          "axis_id": {"type": "string"},
          "label": {"type": "string"},
          "present": {"type": "boolean"},
          "count": {"type": "integer", "minimum": 0},
          "first_date": {"type": ["string", "null"]},
          "last_date": {"type": ["string", "null"]},
          "norm_slug": {"type": ["string", "null"]},
          "norm_articulos": {"type": ["string", "null"]},
          "concepto_slug": {"type": ["string", "null"]},
          "anchor": {"type": ["string", "null"]},
          "official_url": {"type": ["string", "null"], "format": "uri"},
          "official_label": {"type": ["string", "null"]},
          "is_cendoj": {"type": "boolean"},
          "subaxes": {"type": "array", "items": {"type": "object", "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}}},
          "items": {"type": "array", "items": {"$ref": "#/components/schemas/JsonValue"}}
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "LegalReportDocument": {
        "type": "object",
        "required": ["state", "axes", "totals"],
        "properties": {
          "state": {
            "anyOf": [
              {"type": "object", "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}},
              {"type": "null"}
            ]
          },
          "axes": {"type": "array", "items": {"$ref": "#/components/schemas/LegalReportAxis"}},
          "totals": {
            "type": "object",
            "required": ["axes_present", "events_total", "norms_cited"],
            "properties": {
              "axes_present": {"type": "integer", "minimum": 0},
              "events_total": {"type": "integer", "minimum": 0},
              "norms_cited": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": false
      },
      "LegalReportResponse": {
        "type": "object",
        "required": ["ok", "company", "charged", "beta_free", "already_paid", "balance_after", "report"],
        "properties": {
          "ok": {"type": "boolean", "const": true},
          "company": {
            "type": "object",
            "required": ["slug", "name"],
            "properties": {"slug": {"type": "string"}, "name": {"type": "string"}},
            "additionalProperties": false
          },
          "charged": {"type": "integer", "minimum": 0},
          "beta_free": {"type": "boolean"},
          "already_paid": {"type": "boolean"},
          "balance_after": {"type": ["integer", "null"]},
          "report": {"$ref": "#/components/schemas/LegalReportDocument"}
        },
        "additionalProperties": false
      },
      "LegalReportPaymentRequiredError": {
        "oneOf": [
          {
            "type": "object",
            "required": ["error", "cost", "balance", "buy_url"],
            "properties": {
              "error": {"type": "string", "const": "insufficient_credits"},
              "cost": {"type": "integer", "minimum": 0},
              "balance": {"type": "integer"},
              "buy_url": {"type": "string"}
            },
            "additionalProperties": false
          },
          {
            "type": "object",
            "required": ["error"],
            "properties": {"error": {"type": "string", "const": "charge_failed"}},
            "additionalProperties": false
          }
        ]
      },
      "StripeWebhookEventRequest": {
        "type": "object",
        "description": "Stripe Event envelope. The exact signed raw bytes, not a reserialized object, are used for verification. Provider extension fields remain typed JSON and are not reflected to callers.",
        "required": ["id", "type", "data"],
        "properties": {
          "id": {"type": "string", "minLength": 1, "description": "Provider event id and durable idempotency key."},
          "object": {"type": "string", "const": "event"},
          "type": {"type": "string", "minLength": 1},
          "created": {"type": "integer", "minimum": 0},
          "livemode": {"type": "boolean"},
          "api_version": {"type": ["string", "null"]},
          "data": {
            "type": "object",
            "required": ["object"],
            "properties": {
              "object": {"type": "object", "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}},
              "previous_attributes": {"type": "object", "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}}
            },
            "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "StripeSessionResponse": {
        "type": "object",
        "required": [
          "url",
          "session_id"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "session_id": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "BillingSubscription": {
        "type": "object",
        "description": "Authenticated user's current subscription metadata.",
        "properties": {
          "id": {
            "type": "integer"
          },
          "stripe_subscription_id": {
            "type": "string"
          },
          "stripe_customer_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "plan": {
            "type": "string"
          },
          "billing": {
            "type": [
              "string",
              "null"
            ]
          },
          "amount_cents": {
            "type": [
              "integer",
              "null"
            ]
          },
          "currency": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string"
          },
          "current_period_start": {
            "type": [
              "string",
              "null"
            ]
          },
          "current_period_end": {
            "type": [
              "string",
              "null"
            ]
          },
          "cancel_at_period_end": {
            "type": [
              "integer",
              "boolean"
            ]
          },
          "canceled_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "BillingInvoice": {
        "type": "object",
        "description": "Authenticated user's invoice metadata; URLs point to Stripe-hosted documents.",
        "properties": {
          "id": {
            "type": "integer"
          },
          "stripe_invoice_id": {
            "type": "string"
          },
          "invoice_number": {
            "type": [
              "string",
              "null"
            ]
          },
          "amount_paid_cents": {
            "type": [
              "integer",
              "null"
            ]
          },
          "amount_due_cents": {
            "type": [
              "integer",
              "null"
            ]
          },
          "subtotal_cents": {
            "type": [
              "integer",
              "null"
            ]
          },
          "tax_cents": {
            "type": [
              "integer",
              "null"
            ]
          },
          "tax_rate_pct": {
            "type": [
              "number",
              "null"
            ]
          },
          "currency": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": [
              "string",
              "null"
            ]
          },
          "invoice_pdf": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "hosted_invoice_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "period_start": {
            "type": [
              "string",
              "null"
            ]
          },
          "period_end": {
            "type": [
              "string",
              "null"
            ]
          },
          "paid_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string"
          }
        },
        "additionalProperties": {"$ref": "#/components/schemas/JsonValue"}
      },
      "BillingInvoicesResponse": {
        "type": "object",
        "required": [
          "ok",
          "subscription",
          "invoices"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "subscription": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/BillingSubscription"
              },
              {
                "type": "null"
              }
            ]
          },
          "invoices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillingInvoice"
            },
            "maxItems": 50
          }
        },
        "additionalProperties": false
      },
      "CompanyExportItem": {
        "type": "object",
        "required": [
          "slug",
          "name",
          "acts_count"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "cif": {
            "type": [
              "string",
              "null"
            ]
          },
          "province": {
            "type": [
              "string",
              "null"
            ]
          },
          "first_seen": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_seen": {
            "type": [
              "string",
              "null"
            ]
          },
          "acts_count": {
            "type": "integer"
          }
        },
        "additionalProperties": false
      },
      "CompanyExportMeta": {
        "type": "object",
        "required": [
          "total",
          "limit",
          "offset",
          "has_more",
          "generated_at"
        ],
        "properties": {
          "total": {
            "type": "null"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "has_more": {
            "type": "boolean"
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "CompanyExportResponse": {
        "type": "object",
        "required": [
          "meta",
          "items"
        ],
        "properties": {
          "meta": {
            "$ref": "#/components/schemas/CompanyExportMeta"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CompanyExportItem"
            },
            "maxItems": 5000
          }
        },
        "additionalProperties": false
      }
    },
    "parameters": {
      "CsrfHeader": {
        "name": "X-CSRF-Token",
        "in": "header",
        "required": true,
        "description": "Fresh token returned by GET /api/v1/user/me for this authenticated session.",
        "schema": {"type": "string", "minLength": 32, "maxLength": 256}
      },
      "AccountIdempotencyKeyHeader": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "Required for account mutations that reveal a secret. Reuse the same key only for an identical payload. The encrypted response can be replayed for 24 hours; a changed payload or an expired key returns 409.",
        "schema": {
          "type": "string",
          "minLength": 8,
          "maxLength": 128,
          "pattern": "^[A-Za-z0-9][A-Za-z0-9._:\\-]{7,127}$"
        }
      },
      "CompanySlugPath": {
        "name": "slug",
        "in": "path",
        "required": true,
        "description": "Exact corporate slug admitted by company_public_v2; no empty segments, leading/trailing hyphen or repeated separator.",
        "schema": {"type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$", "minLength": 1}
      },
      "IfNoneMatchHeader": {
        "name": "If-None-Match",
        "in": "header",
        "required": false,
        "description": "Optional RFC 9110 entity-tag validator. Weak validators, comma-separated validator lists and `*` are accepted.",
        "schema": {"type": "string", "minLength": 1, "maxLength": 8192}
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request",
        "headers": {
          "Cache-Control": {"$ref": "#/components/headers/NoStoreCacheControl"}
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "headers": {
          "Cache-Control": {"$ref": "#/components/headers/NoStoreCacheControl"}
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Rate limit exceeded",
        "headers": {
          "Retry-After": {
            "description": "Seconds to wait before retrying.",
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Authentication required (no active session)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "ValidationFailed": {
        "description": "The query is lexically valid but outside a documented numeric or length bound, or uses an unsupported indexed combination.",
        "headers": {
          "Cache-Control": {"$ref": "#/components/headers/NoStoreCacheControl"}
        },
        "content": {
          "application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}
        }
      },
      "PayloadTooLarge": {
        "description": "JSON request body exceeds the 65536-byte account API limit.",
        "headers": {
          "Cache-Control": {"$ref": "#/components/headers/NoStoreCacheControl"}
        },
        "content": {
          "application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}
        }
      },
      "InternalServerError": {
        "description": "The bounded operation failed without exposing internal exception details.",
        "headers": {
          "Cache-Control": {"$ref": "#/components/headers/NoStoreCacheControl"}
        },
        "content": {
          "application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}
        }
      },
      "LegalLayerUnavailable": {
        "description": "Controlled fail-closed denial: the required dataset or legal layer is absent, invalid, unsupported or not authorized for this public surface.",
        "headers": {
          "Cache-Control": {"$ref": "#/components/headers/NoStoreCacheControl"}
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {"error": "legal_layer_unavailable", "detail": "Este dataset no esta habilitado para redistribucion publica por la politica de fuentes activa.", "source_catalog_version": "2026-07-12.2"}
          }
        }
      },
      "PublicReadUnavailable": {
        "description": "The public read failed closed because its legal source catalog, subject classification, bounded projection, database helper or required artifact is unavailable. Clients must not infer an empty result.",
        "headers": {
          "Cache-Control": {
            "description": "Unavailable public reads are never cacheable.",
            "schema": {"type": "string", "const": "no-store"}
          },
          "Retry-After": {
            "description": "Optional number of seconds to wait before retrying.",
            "schema": {"type": "integer", "minimum": 1}
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "anyOf": [
                {"$ref": "#/components/schemas/ProjectionUnavailableError"},
                {"$ref": "#/components/schemas/ErrorResponse"}
              ]
            },
            "examples": {
              "legal_layer": {"value": {"error": "legal_layer_unavailable"}},
              "company_identity": {"value": {"error": "company_public_projection_unavailable"}},
              "projection": {"value": {"error": "projection_unavailable", "detail": "La proyección pública requerida no está disponible.", "projection": "wikidata_company_v1"}}
            }
          }
        }
      }
    },
    "headers": {
      "XDataSources": {
        "description": "Comma-separated aliases from the active public source catalog that contributed to the response. Omitted only when a valid exact filter returns an empty representation with zero contributing sources.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "pattern": "^[a-z0-9][a-z0-9_.-]*(,[a-z0-9][a-z0-9_.-]*)*$"
        },
        "example": "borme,placsp"
      },
      "XSourceCatalogVersion": {
        "description": "Mandatory on every successful public GET. Exact version of the legal source catalog used to authorize the response.",
        "schema": {"type": "string", "minLength": 1},
        "example": "2026-07-12.2"
      },
      "XAttributionRequired": {
        "description": "Optional. When present, comma-separated public source aliases whose attribution terms must accompany reuse.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "pattern": "^[a-z0-9][a-z0-9_.-]*(,[a-z0-9][a-z0-9_.-]*)*$"
        },
        "example": "placsp"
      },
      "CompanyCompareContentLocation": {
        "description": "Canonical comparison URL with the two canonical slugs in stable lexical order.",
        "schema": {
          "type": "string",
          "pattern": "^/api/v1/companies/compare\\?slugs=[a-z0-9]+(?:-[a-z0-9]+)*,[a-z0-9]+(?:-[a-z0-9]+)*$"
        },
        "example": "/api/v1/companies/compare?slugs=empresa-a-sa,empresa-b-sl"
      },
      "EntityTag": {
        "description": "Strong generation-bound entity tag for conditional GET.",
        "schema": {
          "type": "string",
          "pattern": "^\"[a-f0-9]{64}\"$"
        }
      },
      "PrivateRevalidationCacheControl": {
        "description": "Caller-specific rate-limit and plan headers make this representation private. A private cache may retain the body but must revalidate every request; shared caches must not store or reuse it.",
        "schema": {
          "type": "string",
          "const": "private, no-cache, must-revalidate"
        }
      },
      "NoStoreCacheControl": {
        "description": "Error responses must not be stored.",
        "schema": {
          "type": "string",
          "const": "no-store"
        }
      },
      "StatsGeneration": {
        "description": "Exact shared generation of the active CCAA, sector, sources and global-counters bundle.",
        "schema": {
          "type": "string",
          "pattern": "^asv1-[a-f0-9]{64}$"
        }
      },
      "CompanyContentLocation": {
        "description": "Present when a safe historical company alias was accepted and processed as its canonical company slug.",
        "schema": {
          "type": "string",
          "pattern": "^/api/v1/(?:company|empresa|grafo)/[a-z0-9]+(?:-[a-z0-9]+)*(?:/.*)?$"
        },
        "example": "/api/v1/company/mercadona-sa"
      },
      "IdempotencyReplayed": {
        "description": "True when this response was recovered from the durable encrypted replay record for the same key and payload.",
        "schema": {"type": "boolean"}
      },
      "IdempotencyKeyExpires": {
        "description": "Unix timestamp after which this key cannot replay the one-time secret and a fresh key is required.",
        "schema": {"type": "integer", "minimum": 1}
      }
    },
    "securitySchemes": {
      "cookieAuth": {
        "type": "apiKey",
        "in": "cookie",
        "name": "ob_sess",
        "description": "Browser session cookie set after login at /mi-cuenta/login. Mutations also require X-CSRF-Token header (obtain via GET /api/v1/user/me)."
      },
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Optional opaque omk_* API credential for public GETs. Anonymous access remains valid; a credential with the operation's x-api-credential-scope (or public:read) selects its account quota. Never place credentials in query strings."
      },
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "opaque omk_* credential",
        "description": "Optional Authorization: Bearer transport for the same opaque omk_* API credential accepted by X-API-Key. It is not a JWT or OAuth access token."
      }
    },
    "x-api-credential-scopes": {
      "public:read": "Umbrella scope accepted by every public read route except bulk exports.",
      "companies:read": "Companies, BORME, CNAE sectors and public aggregates.",
      "people:read": "Documentary mentions of natural persons.",
      "tenders:read": "Sanitized public procurement projections.",
      "legal:read": "BOE mercantile-law corpus.",
      "integrations:read": "Public integration capability catalog."
    }
  }
}
