/** * TypeScript mirror of `docs/API.md` (contract v1). Keep in sync with the FastAPI routers; never widen a shape here to * paper over an API gap — document it in `docs/FRONTEND.md` instead. */ export type Num = number | string | null; export type Metric = | 'activity_score' | 'hiring_momentum_7d' | 'hiring_momentum_30d' | 'hiring_momentum_90d' | 'open_jobs' | 'ai_adoption' | 'product_velocity' | 'geo_expansion' | 'developer_momentum' | 'communication_activity' | 'pricing_activity' | 'leadership_activity' | 'corporate_change_index' | 'anomaly_score' | 'historical_coverage'; export type ConfidenceLabel = 'VERIFIED' | 'HIGH_CONFIDENCE' | 'LIKELY' | 'INFERRED' | 'LOW_CONFIDENCE'; export interface Page { items: T[]; page: number; per_page: number; total: number; pages: number; meta?: Record; } export interface CompanyRef { id: string; slug: string; display_name: string; canonical_domain: string; country: string | null; logo_url: string | null; } export interface CompanyCounts { sensors: number; observations: number; changes: number; events: number; jobs_open: number; } /** Where the one-paragraph description comes from — drives the attribution line under it (spec: never unattributed). */ export type DescriptionSource = 'wikipedia' | 'wikidata' | 'homepage' | 'llm'; /** A monetary fact as stated by its source for one fiscal year — rendered compact with the year, never converted. */ export interface MoneyFact { value: number; currency: string; year: number; } /** Per-field provenance for the enrichment profile (`field` matches a `CompanyProfile` key, e.g. `revenue`, `hq`). */ export interface ProfileSource { field: string; source: string; url: string | null; retrieved_at: string; } export interface CompanySocials { linkedin?: string; x?: string; youtube?: string; facebook?: string; instagram?: string; github?: string; tiktok?: string; crunchbase?: string; } /** * Enrichment profile (Wikidata / Wikipedia / homepage / registries). Every field may be null: the UI hides missing facts * rather than rendering dashes, and every rendered fact carries its source chip. */ export interface CompanyProfile { description: string | null; description_source: DescriptionSource | null; description_url: string | null; description_license: string | null; logo_url: string | null; icon_url: string | null; founded_year: number | null; legal_form: string | null; employees: number | null; employees_year: number | null; revenue: MoneyFact | null; net_income: MoneyFact | null; total_assets: MoneyFact | null; hq: { city: string | null; region: string | null; country: string | null; address: string | null; lat: number | null; lon: number | null }; ticker: string | null; exchange: string | null; isin: string | null; lei: string | null; sec_cik: string | null; public_company: boolean; wikipedia_url: string | null; wikidata_url: string | null; official_website: string | null; phone: string | null; products: string[]; industries: string[]; industry_labels: string[]; socials: CompanySocials; enriched_at: string | null; sources: ProfileSource[]; } /** Flattened, already-formatted fact with provenance (`/companies/{slug}` → `facts`). */ export interface CompanyFact { key: string; label: string; value: string; source: string; url: string | null; retrieved_at: string; } export interface CompanyCard { id: string; slug: string; display_name: string; legal_name: string | null; canonical_domain: string; website: string; description: string | null; industries: string[]; industry_primary: string | null; country: string | null; hq_city: string | null; hq_region: string | null; public_company: boolean; ticker: string | null; exchange: string | null; founded_year: number | null; employees_band: string | null; logo_url: string | null; status: string; onboarding_status: string; importance: number; tier: 1 | 2 | 3 | 4; metrics: Partial>; counts: CompanyCounts; last_event_at: string | null; last_observed_at: string | null; sparkline?: number[]; /** Enrichment profile; absent on API builds that predate it and null-filled while enrichment is pending. */ profile?: CompanyProfile | null; } export interface MetricDetail { metric: Metric | string; value: number; confidence: number; computed_at: string; inputs: Record; formula_version?: string; } /** Corporate-structure kinds the UI groups explicitly; anything else lands under "Other relationships". */ export type RelationshipKind = 'PARENT_OF' | 'SUBSIDIARY_OF' | 'OWNED_BY' | 'OWNER_OF' | 'ACQUIRED_BY' | 'ACQUIRED' | 'COMPETITOR' | 'PARTNER' | (string & {}); export interface Relationship { kind: RelationshipKind; /** Counterpart when it is an atlas company (links to its profile); else only `to_name` is known. */ company: { slug: string; display_name: string; logo_url?: string | null } | null; to_name: string | null; valid_from: string | null; valid_to: string | null; confidence: number; provenance: { source: string; property?: string }; } export interface CompanyDetail extends CompanyCard { aliases: string[]; domains: { domain: string; kind: string }[]; relationships: Relationship[]; /** Sourced key facts (flattened); complements `profile` — the UI merges both and hides nothing that is sourced. */ facts: CompanyFact[]; metrics_detail: MetricDetail[]; sensors_by_surface: Record; coverage: { historical_coverage: number | null; first_observed_at: string | null; days_observed: number; sensor_uptime: number | null }; signals: Signal[]; sparklines: { activity_30d: number[]; hiring_90d: number[] }; } export interface EventSource { source_url: string; surface: string | null; detected_at: string; kind: string; sensor_id: string | null; } export type EventOrigin = 'deterministic' | 'llm' | 'hybrid' | 'backfill'; export type EventStatus = 'active' | 'retracted' | 'duplicate' | 'review'; export interface Event { id: string; company: CompanyRef; event_type: string; event_subtype: string; importance: number; confidence: number; confidence_label: ConfidenceLabel | string; title: string; summary: string | null; old_value: string | null; new_value: string | null; payload: Record; entities: Record; tags: string[]; detected_at: string; effective_at: string | null; published_at: string | null; source_url: string | null; surface: string | null; sensor_id: string | null; change_id: string | null; cluster_id: string | null; origin: EventOrigin; model_name: string | null; prompt_version: string | null; status: EventStatus; sources?: EventSource[]; } export interface EventDetail extends Event { sources: EventSource[]; change: Change | null; } export type SensorTier = 'A' | 'B' | 'C' | 'D' | 'E'; export interface Sensor { id: string; company_id: string; surface: string; connector_id: string; url: string; canonical_url: string; domain: string; status: string; tier: SensorTier; quality_score: number; discovery_confidence: number; discovery_method: string | null; current_interval_s: number; next_run_at: string; last_run_at: string | null; last_success_at: string | null; last_change_at: string | null; last_status: number | null; last_failure_class: string | null; consecutive_failures: number; observation_count: number; snapshot_count: number; change_count: number; meaningful_change_count: number; event_count: number; created_at: string; } export interface SensorDetail extends Sensor { company: CompanyRef; latest_snapshot: Snapshot | null; } export interface Snapshot { id: string; sensor_id: string; version_no: number; fetched_at: string; title: string | null; language: string | null; text_length: number | null; block_count: number | null; extracted_summary: Record; content_hash: string; previous_snapshot_id: string | null; } export interface Block { key: string; kind: string; path: string; text: string; } export interface SnapshotDetail extends Snapshot { text: string; blocks: Block[]; extracted: Record; } export interface BlockDelta { key: string; kind: string; path: string; before: string | null; after: string | null; weight: number; similarity: number | null; } export interface DiffPayload { added: BlockDelta[]; removed: BlockDelta[]; modified: BlockDelta[]; moved: string[]; counts: Record; text_delta_ratio: number; similarity: number; reasons: string[]; } export interface Change { id: string; sensor_id: string; surface: string; company_id: string; detected_at: string; significance: number; kind: string; blocks_added: number; blocks_removed: number; blocks_modified: number; text_delta_ratio: number; similarity: number | null; snapshot_before: string | null; snapshot_after: string; diff?: DiffPayload; structured_delta?: Record; } export interface ChangeDetail extends Change { diff: DiffPayload; structured_delta: Record; events: Event[]; company?: CompanyRef; } export interface SnapshotDiff { before: Snapshot; after: Snapshot; diff: DiffPayload; } export interface Job { id: string; title: string; department: string | null; location_text: string | null; city: string | null; country: string | null; remote: boolean | null; employment_type: string | null; seniority: string | null; url: string | null; posted_at: string | null; first_seen_at: string; last_seen_at: string; removed_at: string | null; status: 'open' | 'no_longer_listed'; is_ai: boolean; } export interface JobsSummary { open: number; new_7d: number; removed_7d: number; ai_open: number; by_country: { country: string; n: number }[]; by_department: { department: string; n: number }[]; remote_ratio: number | null; } export interface JobsPage extends Page { meta?: { summary?: JobsSummary } & Record; summary?: JobsSummary; } export interface Person { id: string; name: string; title: string | null; role_category: string | null; is_executive: boolean; first_seen_at: string; last_seen_at: string; removed_at: string | null; status: string; source_url: string | null; /** `page` = observed on the monitored leadership page (default when absent); `wikidata` = position statement on Wikidata. */ source?: 'wikidata' | 'page'; } export interface Product { id: string; name: string; category: string | null; description: string | null; url: string | null; first_seen_at: string; last_seen_at: string; removed_at: string | null; status: string; } export interface Plan { id: string; plan_name: string; price: number | null; price_text: string | null; currency: string | null; billing_period: string | null; unit: string | null; features: string[]; contact_sales: boolean; version_no: number; valid_from: string; valid_to: string | null; status: string; source_url: string | null; } export interface Location { id: string; kind: string; name: string | null; city: string | null; region: string | null; country: string | null; lat: number | null; lon: number | null; first_seen_at: string; last_seen_at: string; removed_at: string | null; status: string; source_url: string | null; } export interface NewsItem { id: string; title: string; url: string; summary: string | null; category: string | null; published_at: string | null; first_seen_at: string; language: string | null; } export interface MetricPoint { day: string; value: number; confidence: number; } export interface Signal { id: string; company_id: string | null; scope: string; scope_key: string | null; kind: string; strength: number; confidence: number; title: string; explanation: string | null; evidence: Record; window_days: number; detected_at: string; status: string; } // ---------------------------------------------------------------------------------------------------------- platform export interface Stats { companies: number; companies_active: number; sensors: number; sensors_active: number; observations: number; snapshots: number; changes: number; meaningful_changes: number; events: number; jobs_open: number; countries: number; industries: number; observations_today: number; changes_today: number; events_today: number; dataset_started_at: string | null; dataset_age_days: number | null; oldest_history_days: number | null; last_observation_at: string | null; archive: { objects: number; bytes: number }; } export interface GlobalDaily { day: string; companies_active: number; sensors_active: number; observations: number; changes: number; meaningful_changes: number; events: number; events_by_type: Record; jobs_open: number; jobs_new: number; jobs_removed: number; activity_index: number | null; } export interface SystemHealth { sensors_online: number; sensors_failing: number; observations_today: number; events_today: number; countries_covered: number; queue_lag_s: number | null; scheduler_last_tick_at: string | null; fetch_per_min: number | null; success_rate_24h: number | null; } export interface IndustryRow { slug: string; name: string; parent_slug: string | null; companies: number; events_7d: number; events_30d: number; hiring_momentum_30d: number | null; activity_score: number | null; ai_adoption: number | null; top_event_types: string[]; } export interface IndustryDetail extends IndustryRow { description: string | null; companies_list?: CompanyCard[]; events: Event[]; hiring: { open: number; new_30d: number; removed_30d: number; momentum_30d: number | null }; series: MetricPoint[]; countries: { country: string; companies: number }[]; trending: TrendRow[]; } /** `/industries/{slug}` returns `companies: CompanyCard[]` while the row uses `companies: number` — see docs/FRONTEND.md. */ export type IndustryDetailRaw = Omit & { companies: CompanyCard[] | number }; export interface CountryRow { code: string; name: string; region: string | null; companies: number; events_7d: number; events_30d: number; hiring_momentum_30d: number | null; activity_score: number | null; industry_mix: { industry: string; companies: number }[]; lat: number | null; lon: number | null; } export interface CountryDetail extends CountryRow { companies_list?: CompanyCard[]; events: Event[]; movers: CompanyCard[]; new_entrants: CompanyCard[]; series: MetricPoint[]; industries: IndustryRow[]; } export type CountryDetailRaw = Omit & { companies: CompanyCard[] | number }; export interface TrendRow { term: string; mentions: number; companies: number; momentum: number | null; series: number[]; } export interface MapBucket { lat: number; lon: number; country: string; city: string | null; companies: number; events_30d: number; jobs_open: number; top: { slug: string; display_name: string }[]; } export interface ActivityIndex { value: number | null; baseline: number; delta_7d: number | null; delta_30d: number | null; series: MetricPoint[]; by_type: Record; by_country: { key: string; value: number }[]; by_industry: { key: string; value: number }[]; formula_version: string; } export interface Pulse { stats: Stats; live: Event[]; movers: CompanyCard[]; hiring: CompanyCard[]; launches: Event[]; pricing: Event[]; ai: CompanyCard[]; industries: IndustryRow[]; countries: CountryRow[]; trending: TrendRow[]; activity_index: { value: number | null; delta_7d: number | null; series: MetricPoint[] }; map: MapBucket[]; } export type RankingKind = 'most_active' | 'hiring_growth' | 'hiring_decline' | 'product_velocity' | 'ai_active' | 'geo_expansion' | 'developer_momentum' | 'pricing_changes' | 'unusual_activity'; export type RankingWindow = '24h' | '7d' | '30d' | '90d' | '1y'; export interface RankingItem extends CompanyCard { rank: number; value: number; delta: number | null; } export interface Rankings { kind: RankingKind | string; window: RankingWindow | string; items: RankingItem[]; } export interface TimelinePayload { items: (Event & { day: string })[]; days: { day: string; count: number }[]; } export interface CompanyMetrics { current: MetricDetail[]; series: Partial>; } export interface ComparePayload { companies: CompanyCard[]; metrics: Partial>>; series: Record; events_30d: Record>; jobs: Record; locations: Record; } export interface HistoryPayload { sensors: (Sensor & { versions: Snapshot[] })[]; } export interface EventTypes { types: { event_type: string; subtypes: { event_subtype: string; count_30d: number }[]; count_30d: number }[]; } export interface EventSummary { items: { key: string; count: number; delta_pct: number | null }[]; } export interface SearchPayload { query: string; companies: CompanyCard[]; events: Event[]; industries: IndustryRow[]; countries: CountryRow[]; people: (Person & { company: CompanyRef })[]; products: (Product & { company: CompanyRef })[]; took_ms: number; } export interface Suggestion { kind: 'company' | 'industry' | 'country' | 'event_type'; label: string; sublabel: string | null; href: string; } export interface AskPayload { interpretation: Record; answer: string; companies: CompanyCard[]; events: Event[]; sources: string[]; } export interface WatchlistPayload { items: CompanyCard[]; events: Event[]; } export interface AlertCondition { event_types?: string[]; min_importance?: number; metrics?: Partial>; } export interface Alert { id: string; name: string; company: string | null; condition: AlertCondition; channel: 'web' | 'webhook'; target: string | null; created_at: string; status?: string; } export interface AlertDelivery { id: string; alert_id: string; alert_name?: string; event_id: string | null; event?: Event | null; channel: string; status: string; delivered_at: string; } export interface SitemapPayload { items: { slug: string; updated_at: string | null }[]; pages: number; } export interface Methodology { metrics: { metric: string; formula_version: string; description: string; inputs: string[] }[]; significance_bands: Record | { label: string; min: number; max: number }[]; event_types: string[]; confidence_labels: Record | (string | { label: string; min_confidence?: number | null })[]; } // ---------------------------------------------------------------------------------------------------------- admin export interface AdminOverview { companies_by_status: Record; sensors_by_status: Record; sensors_by_tier: Record; queue: { pending: number; running: number; dead: number; oldest_pending_s: number | null }; llm: { pending: number; done_today: number; failed_today: number; budget_left: number | null }; failures_24h_by_class: Record; fetch_rate_1h: number | null; change_rate_1h: number | null; meaningful_rate_1h: number | null; storage: { objects: number; bytes: number }; workers: { name: string; last_seen_at: string; inflight: number }[]; cost_today: { fetch: number; browser: number; llm: number }; } export interface AdminConnector { id: string; name: string; version: string; category: string; enabled: boolean; sensors_active: number; sensors_failing: number; success_rate_24h: number | null; avg_latency_ms: number | null; change_rate_24h: number | null; errors_24h: number; last_run_at: string | null; } export type AdminSensor = Sensor & { company: CompanyRef }; export interface AdminFailure { id: string; sensor_id: string | null; company?: CompanyRef | null; domain: string | null; failure_class: string; status_code: number | null; message: string | null; occurred_at: string; retry_at: string | null; } export interface AdminQueueItem { id: string; kind: string; status: string; priority: number; attempts: number; scheduled_at: string; started_at: string | null; finished_at: string | null; worker: string | null; ref: string | null; error: string | null; } export interface AdminLlmJob { id: string; kind: string; status: string; model: string | null; prompt_version: string | null; change_id: string | null; event_id: string | null; tokens_in: number | null; tokens_out: number | null; cost_estimate: number | null; created_at: string; finished_at: string | null; error: string | null; } export interface AdminReview { id: string; kind: string; status: string; subject: string; ref_id: string | null; company?: CompanyRef | null; reason: string | null; created_at: string; resolved_at: string | null; resolution: string | null; } export interface AdminQuality { coverage: { companies_active_pct: number | null; sensors_active_pct: number | null }; freshness: { sensors_checked_24h_pct: number | null; stale: number }; duplicate_rate: number | null; event_confidence_avg: number | null; unknown_surfaces: number; failed_sensors: number; calibration: { correct: number; duplicate: number; noise: number; misclassified: number }; } export interface AdminCosts { items: { day: string; dimension: string; key: string; units: number; cost_estimate: number }[]; per_1000_companies: number | null; per_million_observations: number | null; per_meaningful_event: number | null; } export type AdminCompany = CompanyCard;