{"openapi":"3.1.0","info":{"title":"Nordic Data API","version":"0.26.0","description":"Agent-native API for Nordic public procurement, Norwegian company data, sanctions screening, ownership, tech-stack intelligence, and event-driven webhooks. All endpoints (except /signup, /signup/verify, /openapi.json, /, /countries, /health) require an X-API-Key header. Get a key at https://nordicdata.cloud.","contact":{"name":"Nordic Data","url":"https://nordicdata.cloud"}},"servers":[{"url":"https://api.nordicdata.cloud"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key"},"AdminToken":{"type":"apiKey","in":"header","name":"x-admin-token"}},"parameters":{"Orgnr":{"name":"orgnr","in":"path","required":true,"description":"9-digit Norwegian organisation number.","schema":{"type":"string","pattern":"^\\d{9}$"}},"Limit":{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":1000,"default":50}},"Page":{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},"Country":{"name":"country","in":"query","schema":{"type":"string","enum":["NOR","SWE","DNK","FIN","ISL"]}}},"responses":{"Unauthorized":{"description":"Missing or invalid X-API-Key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Monthly limit reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"BadRequest":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}},"tags":[{"name":"Account","description":"API-key + signup"},{"name":"Agent buying","description":"Endpoints designed for autonomous agents to discover plans, subscribe with a Stripe payment method, and change plans — no browser, no email round-trip, no Customer Portal"},{"name":"Companies (Norway)","description":"Brønnøysund-sourced Norwegian company data"},{"name":"Companies (Multi-Nordic)","description":"Denmark + Finland company lookups"},{"name":"Persons","description":"Officer network across Norwegian companies"},{"name":"Shareholders","description":"Aksjonærregisteret (Norwegian shareholder registry)"},{"name":"Sanctions","description":"OFAC SDN + EU sanctions screening"},{"name":"Tech","description":"Website tech-stack fingerprinting"},{"name":"Tenders","description":"TED public-procurement notices, 5 Nordic countries"},{"name":"Awards","description":"TED public-procurement contract awards"},{"name":"Webhooks","description":"Event-driven subscriptions"}],"paths":{"/me":{"get":{"tags":["Account"],"summary":"API key info + monthly usage","responses":{"200":{"description":"Plan, limit, used_this_month"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/countries":{"get":{"tags":["Tenders"],"summary":"List supported countries + indexed tender counts","security":[],"responses":{"200":{"description":"Indexed countries"}}}},"/health":{"get":{"tags":["Account"],"summary":"Health check","security":[],"responses":{"200":{"description":"OK"}}}},"/companies/search":{"get":{"tags":["Companies (Norway)"],"summary":"Search Norwegian companies by name, orgnr, or NACE","parameters":[{"name":"q","in":"query","schema":{"type":"string"}},{"name":"orgnr","in":"query","schema":{"type":"string","pattern":"^\\d{9}$"}},{"name":"nace","in":"query","schema":{"type":"string"}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Page"}],"responses":{"200":{"description":"Search results from Brønnøysund Enhetsregisteret"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/companies/{orgnr}":{"get":{"tags":["Companies (Norway)"],"summary":"Norwegian company identity","parameters":[{"$ref":"#/components/parameters/Orgnr"}],"responses":{"200":{"description":"Identity, NACE, addresses, status"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{orgnr}/snapshot":{"get":{"tags":["Companies (Norway)"],"summary":"One-call digest across every data source","parameters":[{"$ref":"#/components/parameters/Orgnr"}],"responses":{"200":{"description":"Identity, accounts, officers, contact, tech, procurement, EU grants, shareholders, sanctions, narrative, with data_completeness score and to_enrich pointers"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/bulk":{"post":{"tags":["Companies (Norway)"],"summary":"Enrich up to 100 Norwegian companies in one call","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orgnrs"],"properties":{"orgnrs":{"type":"array","items":{"type":"string","pattern":"^\\d{9}$"},"maxItems":100},"include":{"type":"array","items":{"type":"string","enum":["officers","accounts"]}}}}}}},"responses":{"200":{"description":"Profiles per orgnr (counts as N requests against monthly limit)"},"400":{"$ref":"#/components/responses/BadRequest"}}}},"/companies/{orgnr}/officers":{"get":{"tags":["Companies (Norway)"],"summary":"Current + historical officers (board, executives, others)","parameters":[{"$ref":"#/components/parameters/Orgnr"}],"responses":{"200":{"description":"Officers grouped by ledelse/styre/andre, with churn signal"}}}},"/companies/{orgnr}/accounts":{"get":{"tags":["Companies (Norway)"],"summary":"Latest annual accounts with computed ratios","parameters":[{"$ref":"#/components/parameters/Orgnr"},{"name":"type","in":"query","schema":{"type":"string","enum":["SELSKAP","KONSERN"]}}],"responses":{"200":{"description":"Income statement, balance sheet, ratios. Free tier returns latest year only."}}}},"/companies/{orgnr}/contact":{"get":{"tags":["Companies (Norway)"],"summary":"Verified emails, phones, named key personnel — 4-layer enrichment","description":"Four-layer enrichment: (1) website crawl for emails/phones/JSON-LD; (2) 1881.no directory fallback; (3) Claude Haiku extraction from already-loaded HTML; (4) Claude Sonnet + Anthropic web_search to find role-tagged emails (IR, media, press, owner relations), labelled phones, and named executives (CEO, CFO, Chair, head of IR/Media) with full role attribution. Layer 4 runs in the background for every company — first request returns layers 1+2+3 fast (<5s), next request returns the fully-enriched cache (<100ms). Strict filtering rejects historical/former employees, single-name entries, and duplicate exclusive roles. Cached 30 days per company.","parameters":[{"$ref":"#/components/parameters/Orgnr"},{"name":"refresh","in":"query","schema":{"type":"boolean"},"description":"Force re-crawl (default uses 30-day cache)."}],"responses":{"200":{"description":"Verified emails, phones, role-labelled contacts (`labels` map keyed by `email:` or `phone:` to role/department), `named_contacts` array of key personnel (name, role, optional email, optional phone), MX-verified `candidates`. `enrichment_in_progress: true` indicates Layer 4 web-search is still running in background — refresh in ~30s for the fully-enriched data."}}}},"/companies/{orgnr}/changes":{"get":{"tags":["Companies (Norway)"],"summary":"Brønnøysund registry change history","parameters":[{"$ref":"#/components/parameters/Orgnr"},{"name":"since","in":"query","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Audit trail of registry updates"}}}},"/companies/{orgnr}/subsidiaries":{"get":{"tags":["Companies (Norway)"],"summary":"Direct subsidiaries (parent → child)","parameters":[{"$ref":"#/components/parameters/Orgnr"}],"responses":{"200":{"description":"Companies that registered this orgnr as parent. Sparse — full ownership in /shareholders."}}}},"/companies/{orgnr}/peer-benchmarks":{"get":{"tags":["Companies (Norway)"],"summary":"Percentile rank vs NACE peer cohort","parameters":[{"$ref":"#/components/parameters/Orgnr"}],"responses":{"200":{"description":"Revenue, margin, ROE, equity-ratio percentiles vs peers in same 2-digit NACE."}}}},"/companies/{orgnr}/narrative":{"get":{"tags":["Companies (Norway)"],"summary":"AI-generated executive summary (Haiku 4.5)","parameters":[{"$ref":"#/components/parameters/Orgnr"}],"responses":{"200":{"description":"One-paragraph narrative from cached profile + accounts + officers"}}}},"/companies/{orgnr}/tender-velocity":{"get":{"tags":["Companies (Norway)"],"summary":"Monthly tender-publication velocity as buyer (cross-Nordic)","parameters":[{"name":"orgnr","in":"path","required":true,"schema":{"type":"string","pattern":"^\\d{6,12}$"}},{"$ref":"#/components/parameters/Country"},{"name":"name","in":"query","schema":{"type":"string"},"description":"Override profile-cache name lookup (use for non-NOR companies)."}],"responses":{"200":{"description":"24-month buyer-name match across all 5 countries by default; narrow with ?country="}}}},"/companies/{orgnr}/contract-wins":{"get":{"tags":["Awards"],"summary":"Public contracts won by a Norwegian company","parameters":[{"$ref":"#/components/parameters/Orgnr"},{"name":"period","in":"query","schema":{"type":"string","pattern":"^\\d+[dwm]$","default":"24m"}},{"$ref":"#/components/parameters/Limit"}],"responses":{"200":{"description":"Awards where this orgnr is winner-identifier in TED can-standard notices"}}}},"/companies/{orgnr}/shareholders":{"get":{"tags":["Shareholders"],"summary":"Shareholders of a Norwegian AS (Aksjonærregisteret)","parameters":[{"$ref":"#/components/parameters/Orgnr"},{"name":"year","in":"query","schema":{"type":"integer"},"description":"Defaults to most recent fiscal year cached."},{"name":"min_pct","in":"query","schema":{"type":"number","minimum":0,"maximum":100}},{"$ref":"#/components/parameters/Limit"}],"responses":{"200":{"description":"Per-shareholder ownership, share count, share class, computed pct."}}}},"/companies/{orgnr}/tech":{"get":{"tags":["Tech"],"summary":"Detected tech stack (Stripe, WordPress, HubSpot, etc.)","parameters":[{"$ref":"#/components/parameters/Orgnr"}],"responses":{"200":{"description":"Cached fingerprint from website crawl. Call /contact first to populate."}}}},"/companies/{orgnr}/sanctions-check":{"get":{"tags":["Sanctions"],"summary":"AML check: company name + cached officers vs OFAC + EU","parameters":[{"$ref":"#/components/parameters/Orgnr"}],"responses":{"200":{"description":"Per-name screening results. Call /officers first to populate the officer list."}}}},"/companies/{orgnr}/notices":{"get":{"tags":["Tenders"],"summary":"Tenders this Norwegian company has been buyer on","parameters":[{"$ref":"#/components/parameters/Orgnr"}],"responses":{"200":{"description":"Joined tender history"}}}},"/companies/bankruptcies":{"get":{"tags":["Companies (Norway)"],"summary":"Currently bankrupt Norwegian companies","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Page"}],"responses":{"200":{"description":"BRREG konkurs flag, paginated"}}}},"/companies/dk/search":{"get":{"tags":["Companies (Multi-Nordic)"],"summary":"Search Danish companies (cvrapi.dk)","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"CVR-based identity. Free tier — owners require paid CVR API."}}}},"/companies/dk/{cvr}":{"get":{"tags":["Companies (Multi-Nordic)"],"summary":"Get Danish company by CVR","parameters":[{"name":"cvr","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"CVR identity + employees + production units"}}}},"/companies/fi/search":{"get":{"tags":["Companies (Multi-Nordic)"],"summary":"Search Finnish companies (PRH/YTJ)","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Y-tunnus-based identity from Finnish PRH avoindata."}}}},"/companies/fi/{ytunnus}":{"get":{"tags":["Companies (Multi-Nordic)"],"summary":"Get Finnish company by Y-tunnus","parameters":[{"name":"ytunnus","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Multilingual name history, addresses; no contact (PRH excludes)."}}}},"/companies/fi/{ytunnus}/financials":{"get":{"tags":["Companies (Multi-Nordic)"],"summary":"List available iXBRL financial periods","parameters":[{"name":"ytunnus","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Periods with download URLs (raw XBRL, parsing not yet exposed)"}}}},"/persons/search":{"get":{"tags":["Persons"],"summary":"Fuzzy name search across cached Norwegian officers","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":2}},{"$ref":"#/components/parameters/Limit"}],"responses":{"200":{"description":"Persons + active role count. Network grows as /companies/{orgnr}/officers is called."}}}},"/persons/{id}":{"get":{"tags":["Persons"],"summary":"A person's full role history across Norwegian companies","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"All cached board/exec/auditor roles"}}}},"/persons/{id}/network":{"get":{"tags":["Persons"],"summary":"People sharing boards with this person (1st-degree)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}},{"$ref":"#/components/parameters/Limit"},{"name":"include_resigned","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Connection graph keyed by shared orgnrs"}}}},"/companies/{orgnr}/path-to/{other_orgnr}":{"get":{"tags":["Persons"],"summary":"Shortest officer-network path between two Norwegian companies","parameters":[{"$ref":"#/components/parameters/Orgnr"},{"name":"other_orgnr","in":"path","required":true,"schema":{"type":"string","pattern":"^\\d{9}$"}},{"name":"max_hops","in":"query","schema":{"type":"integer","minimum":1,"maximum":5,"default":3}},{"name":"include_resigned","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"BFS path as alternating company + person nodes, or null if no path within max_hops"}}}},"/persons/{id}/sanctions-check":{"get":{"tags":["Sanctions"],"summary":"Sanctions screen for a single person","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OFAC + EU matches with confidence scores"}}}},"/sanctions/screen":{"get":{"tags":["Sanctions"],"summary":"Screen any name against OFAC SDN + EU sanctions","parameters":[{"name":"name","in":"query","required":true,"schema":{"type":"string","minLength":2}},{"name":"min_score","in":"query","schema":{"type":"integer","minimum":50,"maximum":100,"default":60}},{"$ref":"#/components/parameters/Limit"}],"responses":{"200":{"description":"Matches with score 60-100. Sources reported dynamically."}}}},"/sanctions/screen-bulk":{"post":{"tags":["Sanctions"],"summary":"Screen up to 200 names in one call","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["names"],"properties":{"names":{"type":"array","items":{"type":"string"},"maxItems":200},"min_score":{"type":"integer","minimum":50,"maximum":100,"default":60},"limit":{"type":"integer","default":5}}}}}},"responses":{"200":{"description":"Per-name match arrays (counts as N requests)"}}}},"/shareholders/portfolio":{"get":{"tags":["Shareholders"],"summary":"Reverse-lookup: companies a person/entity owns shares in","parameters":[{"name":"name","in":"query","schema":{"type":"string"}},{"name":"orgnr","in":"query","schema":{"type":"string","pattern":"^\\d{9}$"}},{"name":"year","in":"query","schema":{"type":"integer"}},{"$ref":"#/components/parameters/Limit"}],"responses":{"200":{"description":"Holdings list with computed ownership pct"}}}},"/tech/{technology}/companies":{"get":{"tags":["Tech"],"summary":"Find Norwegian companies using a specific technology","parameters":[{"name":"technology","in":"path","required":true,"schema":{"type":"string","example":"Stripe"}},{"$ref":"#/components/parameters/Limit"}],"responses":{"200":{"description":"Companies whose website signals use of this tech"}}}},"/tenders/search":{"get":{"tags":["Tenders"],"summary":"Search public-procurement notices across the Nordics (TED + Doffin)","description":"Searches the unified `tenders` table containing notices from two sources: TED (above-EU-threshold notices for all 5 Nordic countries) and Doffin (Norway-only, includes below-EU-threshold notices that TED does not have — small municipal and county procurements). Use the `source` parameter to limit to one or the other.","parameters":[{"$ref":"#/components/parameters/Country"},{"name":"source","in":"query","schema":{"type":"string","enum":["TED","DOFFIN"]},"description":"Filter by data source. TED = EU-threshold notices for all 5 Nordic countries (English titles where available). DOFFIN = all Norwegian notices including below-threshold (Norwegian-language titles + descriptions). Omit to search both."},{"name":"buyer_orgnr","in":"query","schema":{"type":"string","pattern":"^\\d{9}$"},"description":"Filter to tenders published by a specific Norwegian buyer (9-digit organisation number from Brønnøysundregistrene). Doffin notices have orgnr; TED notices may not."},{"name":"q","in":"query","schema":{"type":"string"},"description":"Full-text search query against title and description. Uses a language-agnostic tokenizer so Norwegian (Doffin) and English (TED) both match."},{"name":"cpv","in":"query","schema":{"type":"string"},"description":"CPV (Common Procurement Vocabulary) code. Doffin search-API does not yet expose CPV — TED only."},{"name":"from","in":"query","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","schema":{"type":"string","format":"date"}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Page"}],"responses":{"200":{"description":"Tender notices from both sources, sorted by publication date desc. Each result includes a `source` field (\"TED\" or \"DOFFIN\")."}}}},"/tenders/{id}":{"get":{"tags":["Tenders"],"summary":"Get a single tender notice (TED or Doffin)","description":"Fetches a notice by ID. Accepts either TED publication number (format: number-year, e.g. \"317565-2026\") or Doffin notice ID (format: year-number, e.g. \"2026-108414\"). Response includes a `source` field identifying which database.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9]+-[0-9]+$"},"description":"TED format: \"317565-2026\". Doffin format: \"2026-108414\"."}],"responses":{"200":{"description":"Full notice payload (DB cache or live TED fallback for unknown TED IDs)"}}}},"/tenders/leaderboard":{"get":{"tags":["Tenders"],"summary":"Top public-sector buyers by tender volume","parameters":[{"$ref":"#/components/parameters/Country"},{"name":"cpv","in":"query","schema":{"type":"string"}},{"name":"period","in":"query","schema":{"type":"string","pattern":"^\\d+[dwm]$","default":"12m"}},{"$ref":"#/components/parameters/Limit"}],"responses":{"200":{"description":"Buyer-rank by notice count + total value"}}}},"/awards/search":{"get":{"tags":["Awards"],"summary":"Search awarded public-procurement contracts","parameters":[{"$ref":"#/components/parameters/Country"},{"name":"q","in":"query","schema":{"type":"string"}},{"name":"cpv","in":"query","schema":{"type":"string"}},{"name":"from","in":"query","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","schema":{"type":"string","format":"date"}},{"name":"min_value","in":"query","schema":{"type":"number"}},{"name":"winner_orgnr","in":"query","schema":{"type":"string","pattern":"^\\d{9}$"}},{"name":"winner_name","in":"query","schema":{"type":"string"}},{"name":"buyer_name","in":"query","schema":{"type":"string"}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Page"}],"responses":{"200":{"description":"Awarded contracts with winner + buyer + value + CPV"}}}},"/awards/leaderboard":{"get":{"tags":["Awards"],"summary":"Top contract-winning suppliers","parameters":[{"$ref":"#/components/parameters/Country"},{"name":"period","in":"query","schema":{"type":"string","pattern":"^\\d+[dwm]$","default":"12m"}},{"name":"cpv","in":"query","schema":{"type":"string"}},{"$ref":"#/components/parameters/Limit"}],"responses":{"200":{"description":"Suppliers ranked by contracts won + total value"}}}},"/signup":{"post":{"tags":["Account"],"summary":"Start signup — emails verification code","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"plan":{"type":"string","enum":["free","pro","business"],"default":"free"}}}}}},"responses":{"200":{"description":"Verification email dispatched"},"400":{"$ref":"#/components/responses/BadRequest"}}}},"/signup/verify":{"post":{"tags":["Account"],"summary":"Complete signup — issue API key","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","code"],"properties":{"email":{"type":"string","format":"email"},"code":{"type":"string"}}}}}},"responses":{"200":{"description":"api_key (returned ONCE — store securely)"},"400":{"$ref":"#/components/responses/BadRequest"}}}},"/agent/plans":{"get":{"tags":["Agent buying"],"summary":"List available plans + prices for autonomous buying","description":"Public, unauthenticated. Designed for AI agents to discover what they can buy before calling /agent/subscribe. Returns plan IDs, monthly EUR prices, monthly request limits, and the corresponding purchase channel.","security":[],"responses":{"200":{"description":"Array of plans with pricing + tax + payment guidance"}}}},"/agent/subscribe":{"post":{"tags":["Agent buying"],"summary":"Subscribe to a paid plan with a Stripe payment method — returns API key in response","description":"Public, unauthenticated. Designed for AI agents to subscribe end-to-end in a single API call: provide email, plan, country, and a Stripe PaymentMethod ID (pm_xxx). Server attaches the card to a customer, creates a subscription with auto-charge, and returns a working API key in the response body. No browser, no Customer Portal, no email round-trip. If a free key already exists for this email, it is upgraded in place. If a paid subscription already exists, the request is rejected with 409 — use /agent/change-plan with X-API-Key instead.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","plan","payment_method","country"],"properties":{"email":{"type":"string","format":"email","description":"Owner email. Must be unique among active paid subscriptions."},"plan":{"type":"string","enum":["starter","builder","pro","business"],"description":"Plan ID. See GET /agent/plans for prices and limits."},"payment_method":{"type":"string","pattern":"^pm_","description":"Stripe PaymentMethod ID. In test mode, pm_card_visa works."},"country":{"type":"string","pattern":"^[A-Z]{2}$","description":"ISO 3166-1 alpha-2 billing country (e.g. NO, SE, DE, US). Required for MVA / VAT calculation."},"agent_name":{"type":"string","maxLength":80,"description":"Optional free-text label stored on the API key and Stripe customer for your bookkeeping."}}}}}},"responses":{"200":{"description":"Subscription active. Body contains api_key (shown ONCE — store it), plan, monthly_limit, subscription_id, customer_id, next_renewal."},"400":{"$ref":"#/components/responses/BadRequest"},"402":{"description":"Card declined or payment requires additional auth (e.g. 3DS). Body includes Stripe code and subscription_id when applicable."},"409":{"description":"An active paid subscription already exists for this email. Use POST /agent/change-plan with the existing X-API-Key."},"503":{"description":"Stripe not configured on server."}}}},"/agent/change-plan":{"post":{"tags":["Agent buying"],"summary":"Upgrade or downgrade an active subscription in place — authenticated by API key","description":"Authenticated with X-API-Key. Updates the existing Stripe subscription to a new plan with prorated billing. The API key is unchanged — agents continue using the same key after the plan change. Only plan and monthly_limit on /me reflect the new tier.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["plan"],"properties":{"plan":{"type":"string","enum":["starter","builder","pro","business"],"description":"Target plan ID."}}}}}},"responses":{"200":{"description":"Plan changed. Body includes new plan, monthly_limit, subscription_id, next_renewal, and a human-readable message."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"503":{"description":"Stripe not configured on server."}}}},"/subscriptions":{"post":{"tags":["Webhooks"],"summary":"Create a webhook subscription","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["webhook_url"],"properties":{"webhook_url":{"type":"string","format":"uri"},"event_type":{"type":"string","enum":["tender.published","sanctions.added","company.bankruptcy","company.officer_change"],"default":"tender.published"},"filter":{"type":"object","description":"Per-event filter object. See /openapi.json or POST response notes for keys."}}}}}},"responses":{"200":{"description":"Subscription with signing_secret (returned ONCE)"}}},"get":{"tags":["Webhooks"],"summary":"List your subscriptions","responses":{"200":{"description":"Per-key subscription list"}}}},"/subscriptions/{id}":{"delete":{"tags":["Webhooks"],"summary":"Delete a subscription","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"deleted: 1"}}}}}}