{"openapi":"3.1.0","info":{"title":"Platphorm Atlas API","description":"\n# Platphorm Atlas v0 - JA4 Threat Intelligence API\n\nReal-time JA4 fingerprint analysis and threat intelligence platform.\n\n## Overview\n\nAtlas provides APIs for:\n- **Ingesting** JA4 fingerprint observations from sensors (Vercel Firewall, Zeek, WAF, etc.)\n- **Looking up** fingerprints with enrichment from JA4DB\n- **Querying** observations, campaigns, infrastructure, and threat data\n- **Managing** fingerprint labels, severity, and notes\n- **Monitoring** multiple Vercel projects\n\n## Authentication\n\nAll write endpoints (ingest) require a Bearer token. Include in the Authorization header:\n\n```\nAuthorization: Bearer <your_token>\n```\n\nTokens are configured via the `JA4DB_ALLOWED_TOKENS` environment variable (comma-separated).\n\n## Rate Limiting\n\n- Ingest endpoints: 10,000 requests/minute per token\n- Read endpoints: 1,000 requests/minute per IP\n- Lookup endpoints: 100 requests/minute per IP\n\n## JA4 Fingerprint Types\n\n| Type | Description |\n|------|-------------|\n| ja4 | TLS Client Hello fingerprint |\n| ja4h | HTTP Client fingerprint |\n| ja4s | TLS Server Hello fingerprint |\n| ja4t | TCP fingerprint |\n| ja4x | X.509 Certificate fingerprint |\n| ja4ssh | SSH fingerprint |\n| ja4l | Light fingerprint (truncated) |\n| ja4d | Domain fingerprint |\n\n    ","version":"0.1.0","contact":{"name":"Platphorm Atlas Support","url":"https://atlas.platphormnews.com"},"license":{"name":"MIT","url":"https://opensource.org/licenses/MIT"}},"servers":[{"url":"https://atlas.platphormnews.com","description":"Production"},{"url":"http://localhost:3000","description":"Local Development"}],"tags":[{"name":"Ingest","description":"Endpoints for ingesting JA4 fingerprint observations"},{"name":"Lookup","description":"Query and lookup fingerprint data"},{"name":"Projects","description":"Multi-project management and monitoring"},{"name":"Stats","description":"Dashboard statistics and metrics"},{"name":"Observations","description":"Raw observation data from sensors"},{"name":"Campaigns","description":"Threat campaign management"},{"name":"Infrastructure","description":"Network infrastructure tracking"},{"name":"Health","description":"System health and monitoring"},{"name":"Sensors","description":"Sensor registration and management"},{"name":"Alerts","description":"Security alert management and feeds"},{"name":"Actors","description":"Threat actor tracking and attribution"},{"name":"Firewall","description":"Firewall rule management for automated blocking"}],"paths":{"/api/ingest/http":{"post":{"tags":["Ingest"],"summary":"Ingest JA4 observation","description":"\nIngests a single JA4 fingerprint observation from a sensor.\n\nThis endpoint is designed for:\n- Vercel Firewall middleware integration\n- Zeek network sensors\n- Custom WAF implementations\n- Any system that can extract JA4 fingerprints\n\nThe observation will be stored and correlated with existing fingerprint data.\n        ","operationId":"ingestObservation","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestPayload"},"examples":{"vercelMiddleware":{"summary":"From Vercel Middleware","value":{"ts":1733260800000,"ja4":"t13d1517h2_8daaf6152771_b0da82dd1658","ja3":null,"sensor":"myapp-prod","env":"production","projectId":"prj_xxxxxxxxxxxx","projectUrl":"myapp.vercel.app","vercelRegion":"iad1","path":"/api/users","method":"GET","ip":"203.0.113.42"}},"zeekSensor":{"summary":"From Zeek Sensor","value":{"ts":1733260800000,"ja4":"t13d1517h2_8daaf6152771_b0da82dd1658","ja4s":"t120300_c02b_a56c0d24d0a9","sensor":"zeek-lab-1","env":"lab","ip":"10.0.1.50"}}}}}},"responses":{"200":{"description":"Observation ingested successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"id":{"type":"integer","example":12345},"message":{"type":"string","example":"Observation ingested successfully"}}}}}},"401":{"description":"Missing or invalid authorization header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Invalid token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/lookup":{"get":{"tags":["Lookup"],"summary":"Lookup fingerprint","description":"\nLookup detailed information about a JA4 fingerprint.\n\nReturns:\n- Internal fingerprint data (label, severity, notes)\n- JA4DB enrichment (application, OS, category)\n- Observation statistics (total hits, first/last seen, unique IPs/sensors)\n- Recent observations\n- Associated threat campaigns\n        ","operationId":"lookupFingerprint","parameters":[{"name":"fingerprint","in":"query","required":true,"description":"JA4 fingerprint value to lookup","schema":{"type":"string","example":"t13d1517h2_8daaf6152771_b0da82dd1658"}}],"responses":{"200":{"description":"Fingerprint data retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookupResponse"}}}},"400":{"description":"Missing fingerprint parameter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/stats":{"get":{"tags":["Stats"],"summary":"Get dashboard statistics","description":"Returns overall platform statistics for the dashboard.","operationId":"getStats","responses":{"200":{"description":"Statistics retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatsResponse"}}}}}}},"/api/observations":{"get":{"tags":["Observations"],"summary":"List observations","description":"Returns paginated list of raw observations from all sensors.","operationId":"listObservations","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","schema":{"type":"integer","default":1,"minimum":1}},{"name":"limit","in":"query","description":"Results per page","schema":{"type":"integer","default":50,"minimum":1,"maximum":100}},{"name":"sensor","in":"query","description":"Filter by sensor name","schema":{"type":"string"}},{"name":"ja4","in":"query","description":"Filter by JA4 fingerprint","schema":{"type":"string"}}],"responses":{"200":{"description":"Observations retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObservationsResponse"}}}}}}},"/api/campaigns":{"get":{"tags":["Campaigns"],"summary":"List campaigns","description":"Returns all threat campaigns with their associated fingerprints.","operationId":"listCampaigns","responses":{"200":{"description":"Campaigns retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignsResponse"}}}}}}},"/api/infrastructure":{"get":{"tags":["Infrastructure"],"summary":"List infrastructure","description":"Returns tracked infrastructure (IPs, domains, ASNs, etc.).","operationId":"listInfrastructure","parameters":[{"name":"kind","in":"query","description":"Filter by infrastructure type","schema":{"type":"string","enum":["ip","domain","asn","cert_sha256"]}}],"responses":{"200":{"description":"Infrastructure retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InfrastructureResponse"}}}}}}},"/api/fingerprints/label":{"post":{"tags":["Lookup"],"summary":"Label fingerprint","description":"Add or update label, severity, and notes for a fingerprint.","operationId":"labelFingerprint","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabelPayload"}}}},"responses":{"200":{"description":"Fingerprint labeled successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"integer"}}}}}}}}},"/api/health":{"get":{"tags":["Health"],"summary":"Health check","description":"Returns system health status including database connectivity.","operationId":"healthCheck","responses":{"200":{"description":"System healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"503":{"description":"System unhealthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/api/projects":{"get":{"tags":["Projects"],"summary":"List projects","description":"\nReturns all monitored Vercel projects with real-time statistics.\n\nEach project includes:\n- Total observations and unique fingerprints\n- Activity metrics (24h, 1h)\n- Threat indicators (critical, high counts)\n- Last seen timestamp\n        ","operationId":"listProjects","responses":{"200":{"description":"Projects retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Project"}}}}}}},"post":{"tags":["Projects"],"summary":"Add project","description":"\nAdd a new Vercel project to monitor for JA4 fingerprint observations.\n\nThe project_id must be a valid Vercel project ID (starts with 'prj_').\nOnce added, all observations from this project will be automatically correlated.\n        ","operationId":"addProject","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectCreate"},"example":{"project_id":"prj_xxxxxxxxxxxxxxxxxxxx","name":"My Production App","description":"Main production deployment","environment":"production"}}}},"responses":{"201":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Project ID already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/projects/{id}":{"get":{"tags":["Projects"],"summary":"Get project details","description":"Returns detailed statistics for a specific project.","operationId":"getProject","parameters":[{"name":"id","in":"path","required":true,"description":"Project database ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"Project retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"404":{"description":"Project not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Projects"],"summary":"Update project","description":"Update project name, description, environment, or status.","operationId":"updateProject","parameters":[{"name":"id","in":"path","required":true,"description":"Project database ID","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectUpdate"}}}},"responses":{"200":{"description":"Project updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"404":{"description":"Project not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Projects"],"summary":"Delete project","description":"Remove a project from monitoring. Observations are not deleted.","operationId":"deleteProject","parameters":[{"name":"id","in":"path","required":true,"description":"Project database ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"Project deleted","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"project":{"type":"object","properties":{"project_id":{"type":"string"},"name":{"type":"string"}}}}}}}},"404":{"description":"Project not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/ingest/zeek":{"post":{"tags":["Ingest"],"summary":"Ingest Zeek SSL/TLS logs","description":"\nIngest JA4 fingerprint observations from Zeek network sensors.\n\nAccepts Zeek ssl.log JSON format (either a single record or wrapped in a logs array).\nTimestamps may be epoch floats (Zeek native) or ISO-8601 strings.\n        ","operationId":"ingestZeek","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZeekIngestPayload"},"examples":{"zeekSSL":{"summary":"Zeek ssl.log batch","value":{"sensor":"zeek-prod-1","log_type":"ssl","logs":[{"ts":1733260800,"uid":"CXKd3f1pXP5lMcHS5g","id.orig_h":"192.168.1.100","id.orig_p":54321,"id.resp_h":"93.184.216.34","id.resp_p":443,"version":"TLSv13","cipher":"TLS_AES_128_GCM_SHA256","server_name":"example.com","ja4":"t13d1517h2_8daaf6152771_b0da82dd1658","established":true}]}}}}}},"responses":{"200":{"description":"Logs ingested successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"processed":{"type":"integer","example":10},"failed":{"type":"integer","example":0},"errors":{"type":"array","items":{"type":"string"}}}}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/ingest/suricata":{"post":{"tags":["Ingest"],"summary":"Ingest Suricata EVE JSON logs","description":"\nIngest JA4 fingerprint observations from Suricata IDS/IPS sensors.\n\nAccepts both standard JSON (with `events` array) and newline-delimited\nEVE JSON (`application/x-ndjson`). Only TLS events with JA4 data are processed.\n        ","operationId":"ingestSuricata","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuricataIngestPayload"},"examples":{"suricataTLS":{"summary":"Suricata EVE JSON TLS event","value":{"sensor":"suricata-edge-1","events":[{"timestamp":"2024-01-15T10:30:00.123456+0000","event_type":"tls","src_ip":"192.168.1.100","src_port":54321,"dest_ip":"93.184.216.34","dest_port":443,"tls":{"version":"TLS 1.3","sni":"example.com","ja4":"t13d1517h2_8daaf6152771_b0da82dd1658"}}]}}}},"application/x-ndjson":{"schema":{"type":"string","description":"Newline-delimited EVE JSON — one event per line. Non-TLS events are skipped automatically."}}}},"responses":{"200":{"description":"Events ingested","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"processed":{"type":"integer"},"skipped":{"type":"integer"},"failed":{"type":"integer"},"errors":{"type":"array","items":{"type":"string"}}}}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/ingest/batch":{"post":{"tags":["Ingest"],"summary":"Batch ingest observations","description":"\nIngest multiple JA4 fingerprint observations in a single request.\n\nSupports JSON, CSV, and NDJSON formats. Maximum batch size is configurable\n(default 1000 records). Optional deduplication flag removes duplicate fingerprints.\n        ","operationId":"batchIngest","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchIngestPayload"},"examples":{"jsonBatch":{"summary":"JSON batch","value":{"format":"json","source":"my-scanner","deduplicate":true,"records":[{"ja4":"t13d1517h2_8daaf6152771_b0da82dd1658","src_ip":"192.168.1.100","sensor":"lab-sensor","ts":1733260800000}]}}}}}},"responses":{"200":{"description":"Batch processed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"total":{"type":"integer"},"processed":{"type":"integer"},"skipped":{"type":"integer"},"failed":{"type":"integer"},"errors":{"type":"array","items":{"type":"string"}}}}}}},"400":{"description":"Invalid payload or batch too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/sensors":{"get":{"tags":["Sensors"],"summary":"List sensors","description":"Returns all registered sensors with their last-seen timestamps and observation counts.","operationId":"listSensors","responses":{"200":{"description":"Sensors retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"sensors":{"type":"array","items":{"$ref":"#/components/schemas/Sensor"}}}}}}}}}},"/api/alerts":{"get":{"tags":["Alerts"],"summary":"List alerts","description":"Returns security alerts with optional filtering by status and severity.","operationId":"listAlerts","parameters":[{"name":"status","in":"query","description":"Filter by alert status","schema":{"type":"string","enum":["active","acknowledged","resolved"]}},{"name":"severity","in":"query","description":"Filter by severity","schema":{"type":"string","enum":["critical","high","medium","low"]}},{"name":"limit","in":"query","description":"Maximum number of alerts to return","schema":{"type":"integer","default":50,"maximum":500}}],"responses":{"200":{"description":"Alerts retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/Alert"}}}}}}}}},"post":{"tags":["Alerts"],"summary":"Create alert","description":"Create a new security alert.","operationId":"createAlert","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertCreate"},"example":{"title":"Critical Fingerprint Detected","severity":"critical","alert_type":"threat_detected","description":"Cobalt Strike beacon fingerprint observed from 203.0.113.42","fingerprint":"t13d1516h2_8daaf6152771_02713d6af862"}}}},"responses":{"201":{"description":"Alert created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Alert"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/alerts/feed":{"get":{"tags":["Alerts"],"summary":"Real-time alert feed","description":"Returns the latest alerts for real-time dashboard display, sorted by creation time descending.","operationId":"getAlertFeed","responses":{"200":{"description":"Alert feed retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/Alert"}}}}}}}}}},"/api/actors":{"get":{"tags":["Actors"],"summary":"List threat actors","description":"Returns all tracked threat actors with associated campaigns and fingerprints.","operationId":"listActors","responses":{"200":{"description":"Actors retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"actors":{"type":"array","items":{"$ref":"#/components/schemas/Actor"}}}}}}}}},"post":{"tags":["Actors"],"summary":"Create threat actor","description":"Add a new threat actor to track.","operationId":"createActor","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActorCreate"},"example":{"name":"APT-29 Cozy Bear","description":"Russian state-sponsored APT group","threat_level":"critical","origin_country":"RU"}}}},"responses":{"201":{"description":"Actor created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Actor"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/actors/{id}":{"get":{"tags":["Actors"],"summary":"Get actor details","description":"Returns detailed information about a specific threat actor including linked campaigns.","operationId":"getActor","parameters":[{"name":"id","in":"path","required":true,"description":"Actor ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"Actor retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Actor"}}}},"404":{"description":"Actor not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/firewall/rules":{"get":{"tags":["Firewall"],"summary":"List firewall rules","description":"Returns all configured firewall rules for automated blocking based on JA4 fingerprints.","operationId":"listFirewallRules","responses":{"200":{"description":"Firewall rules retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"rules":{"type":"array","items":{"$ref":"#/components/schemas/FirewallRule"}}}}}}}}},"post":{"tags":["Firewall"],"summary":"Create firewall rule","description":"Create a new rule to block or flag traffic matching a JA4 fingerprint pattern.","operationId":"createFirewallRule","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FirewallRuleCreate"},"example":{"name":"Block Cobalt Strike","rule_type":"block","fingerprint_pattern":"t13d1516h2_8daaf6152771_02713d6af862","enabled":true,"priority":100}}}},"responses":{"201":{"description":"Rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FirewallRule"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/projects/validate":{"post":{"tags":["Projects"],"summary":"Validate project ID","description":"Validate Vercel project ID format before adding.","operationId":"validateProjectId","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["project_id"],"properties":{"project_id":{"type":"string","example":"prj_xxxxxxxxxxxxxxxxxxxx"}}}}}},"responses":{"200":{"description":"Validation result","content":{"application/json":{"schema":{"type":"object","properties":{"valid":{"type":"boolean"},"project_id":{"type":"string"},"format":{"type":"string"},"error":{"type":"string"}}}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API token for write operations"}},"schemas":{"IngestPayload":{"type":"object","properties":{"ts":{"type":"integer","description":"Unix timestamp in milliseconds","example":1733260800000},"ja4":{"type":"string","description":"JA4 TLS fingerprint","example":"t13d1517h2_8daaf6152771_b0da82dd1658"},"ja3":{"type":"string","nullable":true,"description":"JA3 fingerprint (legacy)"},"ja4h":{"type":"string","nullable":true,"description":"JA4H HTTP fingerprint"},"ja4t":{"type":"string","nullable":true,"description":"JA4T TCP fingerprint"},"ja4s":{"type":"string","nullable":true,"description":"JA4S Server Hello fingerprint"},"ja4x":{"type":"string","nullable":true,"description":"JA4X Certificate fingerprint"},"ja4ssh":{"type":"string","nullable":true,"description":"JA4SSH fingerprint"},"sensor":{"type":"string","description":"Sensor/source identifier","example":"myapp-prod"},"env":{"type":"string","description":"Environment (production, staging, etc.)","example":"production"},"projectId":{"type":"string","description":"Vercel project ID"},"projectUrl":{"type":"string","description":"Project URL/hostname"},"vercelRegion":{"type":"string","description":"Vercel edge region","example":"iad1"},"path":{"type":"string","description":"HTTP request path","example":"/api/users"},"method":{"type":"string","description":"HTTP method","example":"GET"},"ip":{"type":"string","description":"Client IP address","example":"203.0.113.42"}}},"LookupResponse":{"type":"object","properties":{"fingerprint":{"type":"object","nullable":true,"description":"Internal fingerprint data","properties":{"id":{"type":"integer"},"ja4_value":{"type":"string"},"fingerprint_type":{"type":"string"},"label":{"type":"string","nullable":true},"confidence":{"type":"number","nullable":true},"severity":{"type":"integer","nullable":true},"notes":{"type":"string","nullable":true},"application":{"type":"string","nullable":true},"os":{"type":"string","nullable":true},"category":{"type":"string","nullable":true}}},"ja4db":{"type":"object","nullable":true,"description":"JA4DB enrichment data"},"stats":{"type":"object","properties":{"total_observations":{"type":"integer"},"first_seen":{"type":"string","format":"date-time"},"last_seen":{"type":"string","format":"date-time"},"unique_sensors":{"type":"integer"},"unique_ips":{"type":"integer"}}},"recentObservations":{"type":"array","items":{"$ref":"#/components/schemas/Observation"}},"campaigns":{"type":"array","items":{"$ref":"#/components/schemas/Campaign"}}}},"StatsResponse":{"type":"object","properties":{"totalObservations":{"type":"integer"},"totalFingerprints":{"type":"integer"},"totalCampaigns":{"type":"integer"},"recentActivity":{"type":"integer"},"topFingerprints":{"type":"array","items":{"type":"object","properties":{"fingerprint_value":{"type":"string"},"hits":{"type":"integer"},"first_seen":{"type":"string"},"last_seen":{"type":"string"},"label":{"type":"string","nullable":true},"severity":{"type":"integer","nullable":true}}}},"severityBreakdown":{"type":"array","items":{"type":"object","properties":{"severity_level":{"type":"string"},"count":{"type":"integer"}}}}}},"Observation":{"type":"object","properties":{"id":{"type":"integer"},"ts":{"type":"string","format":"date-time"},"sensor_name":{"type":"string"},"src_ip":{"type":"string"},"http_host":{"type":"string"},"http_path":{"type":"string"},"ja4":{"type":"string"},"ja4h":{"type":"string"},"extra":{"type":"object"}}},"Campaign":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"description":{"type":"string"},"status":{"type":"string"},"first_seen":{"type":"string"},"last_seen":{"type":"string"},"confidence":{"type":"number"}}},"ObservationsResponse":{"type":"object","properties":{"observations":{"type":"array","items":{"$ref":"#/components/schemas/Observation"}},"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"}}},"CampaignsResponse":{"type":"object","properties":{"campaigns":{"type":"array","items":{"$ref":"#/components/schemas/Campaign"}}}},"InfrastructureResponse":{"type":"object","properties":{"infrastructure":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"kind":{"type":"string"},"value":{"type":"string"},"first_seen":{"type":"string"},"last_seen":{"type":"string"},"meta":{"type":"object"}}}}}},"LabelPayload":{"type":"object","required":["ja4_value"],"properties":{"ja4_value":{"type":"string","description":"JA4 fingerprint value"},"fingerprint_type":{"type":"string","default":"ja4"},"label":{"type":"string","description":"Human-readable label"},"severity":{"type":"integer","minimum":0,"maximum":100},"notes":{"type":"string"}}},"HealthResponse":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","degraded","unhealthy"]},"timestamp":{"type":"string","format":"date-time"},"version":{"type":"string"},"environment":{"type":"string"},"region":{"type":"string"},"checks":{"type":"object","properties":{"database":{"type":"object","properties":{"status":{"type":"string"},"latencyMs":{"type":"integer"},"error":{"type":"string"}}},"observations":{"type":"object","properties":{"last24h":{"type":"integer"},"lastHour":{"type":"integer"}}}}}}},"Error":{"type":"object","properties":{"error":{"type":"string"}}},"Project":{"type":"object","properties":{"id":{"type":"integer","example":1},"project_id":{"type":"string","example":"prj_xxxxxxxxxxxxxxxxxxxx","description":"Vercel project ID"},"name":{"type":"string","example":"My Production App"},"description":{"type":"string","nullable":true},"environment":{"type":"string","enum":["production","preview","development"],"example":"production"},"status":{"type":"string","enum":["active","paused","archived"],"example":"active"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"last_seen":{"type":"string","format":"date-time","nullable":true},"total_observations":{"type":"integer","example":15420},"unique_fingerprints":{"type":"integer","example":234},"observations_24h":{"type":"integer","example":1250},"observations_1h":{"type":"integer","example":52},"last_observation":{"type":"string","format":"date-time","nullable":true},"critical_threats":{"type":"integer","example":3},"high_threats":{"type":"integer","example":12},"meta":{"type":"object","nullable":true}}},"ProjectCreate":{"type":"object","required":["project_id","name"],"properties":{"project_id":{"type":"string","pattern":"^prj_[a-zA-Z0-9]{24,32}$","example":"prj_xxxxxxxxxxxxxxxxxxxx","description":"Vercel project ID (must start with 'prj_')"},"name":{"type":"string","minLength":1,"maxLength":255,"example":"My Production App"},"description":{"type":"string","nullable":true,"example":"Main production deployment"},"environment":{"type":"string","enum":["production","preview","development"],"default":"production"},"meta":{"type":"object","nullable":true,"description":"Additional metadata as JSON"}}},"ProjectUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"description":{"type":"string","nullable":true},"environment":{"type":"string","enum":["production","preview","development"]},"status":{"type":"string","enum":["active","paused","archived"]},"meta":{"type":"object","nullable":true}}},"Sensor":{"type":"object","properties":{"id":{"type":"integer","example":1},"sensor_id":{"type":"string","example":"zeek-prod-1"},"name":{"type":"string","example":"Production Zeek Sensor"},"sensor_type":{"type":"string","enum":["web","zeek","suricata","vercel","custom"],"example":"zeek"},"project_id":{"type":"string","nullable":true,"example":"prj_xxxxxxxxxxxxxxxxxxxx"},"last_seen":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time"},"observation_count":{"type":"integer","example":50420}}},"Alert":{"type":"object","properties":{"id":{"type":"integer","example":42},"title":{"type":"string","example":"Critical Fingerprint Detected"},"severity":{"type":"string","enum":["critical","high","medium","low","info"],"example":"critical"},"alert_type":{"type":"string","example":"threat_detected"},"status":{"type":"string","enum":["active","acknowledged","resolved"],"example":"active"},"description":{"type":"string","nullable":true},"fingerprint":{"type":"string","nullable":true,"example":"t13d1516h2_8daaf6152771_02713d6af862"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"AlertCreate":{"type":"object","required":["title","severity","alert_type"],"properties":{"title":{"type":"string","minLength":1,"maxLength":500},"severity":{"type":"string","enum":["critical","high","medium","low","info"]},"alert_type":{"type":"string","example":"threat_detected"},"description":{"type":"string","nullable":true},"fingerprint":{"type":"string","nullable":true}}},"Actor":{"type":"object","properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"APT-29 Cozy Bear"},"description":{"type":"string","nullable":true},"threat_level":{"type":"string","enum":["critical","high","medium","low"],"nullable":true,"example":"critical"},"origin_country":{"type":"string","nullable":true,"example":"RU"},"first_seen":{"type":"string","format":"date-time","nullable":true},"last_seen":{"type":"string","format":"date-time","nullable":true},"campaign_count":{"type":"integer","example":3},"created_at":{"type":"string","format":"date-time"}}},"ActorCreate":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"description":{"type":"string","nullable":true},"threat_level":{"type":"string","enum":["critical","high","medium","low"],"nullable":true},"origin_country":{"type":"string","nullable":true,"maxLength":2}}},"FirewallRule":{"type":"object","properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Block Cobalt Strike"},"rule_type":{"type":"string","enum":["block","flag","allow","rate_limit"],"example":"block"},"fingerprint_pattern":{"type":"string","example":"t13d1516h2_8daaf6152771_02713d6af862"},"enabled":{"type":"boolean","example":true},"priority":{"type":"integer","example":100},"match_count":{"type":"integer","example":42},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"FirewallRuleCreate":{"type":"object","required":["name","rule_type","fingerprint_pattern"],"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"rule_type":{"type":"string","enum":["block","flag","allow","rate_limit"]},"fingerprint_pattern":{"type":"string","description":"Exact fingerprint value or regex pattern"},"enabled":{"type":"boolean","default":true},"priority":{"type":"integer","default":100,"minimum":1,"maximum":1000}}},"ZeekIngestPayload":{"type":"object","required":["logs"],"properties":{"sensor":{"type":"string","description":"Sensor identifier","example":"zeek-prod-1"},"log_type":{"type":"string","enum":["ssl","ja4","conn","http"],"default":"ssl"},"logs":{"type":"array","description":"Array of Zeek ssl.log entries","items":{"type":"object","properties":{"ts":{"type":"number","description":"Epoch timestamp (Zeek seconds)","example":1733260800},"uid":{"type":"string","description":"Zeek connection UID"},"id.orig_h":{"type":"string","description":"Source IP"},"id.orig_p":{"type":"integer","description":"Source port"},"id.resp_h":{"type":"string","description":"Destination IP"},"id.resp_p":{"type":"integer","description":"Destination port"},"version":{"type":"string","description":"TLS version"},"cipher":{"type":"string"},"server_name":{"type":"string","description":"SNI hostname"},"ja4":{"type":"string"},"ja4s":{"type":"string"},"ja4h":{"type":"string"},"ja4x":{"type":"string"},"ja4t":{"type":"string"},"ja4ssh":{"type":"string"},"ja3":{"type":"string","description":"JA3 legacy fingerprint"},"ja3s":{"type":"string"},"established":{"type":"boolean"}}}}}},"SuricataIngestPayload":{"type":"object","required":["events"],"properties":{"sensor":{"type":"string","description":"Sensor identifier","example":"suricata-edge-1"},"events":{"type":"array","description":"Array of Suricata EVE JSON TLS events","items":{"type":"object","properties":{"timestamp":{"type":"string","format":"date-time"},"event_type":{"type":"string","enum":["tls","http","dns","alert"]},"src_ip":{"type":"string"},"src_port":{"type":"integer"},"dest_ip":{"type":"string"},"dest_port":{"type":"integer"},"tls":{"type":"object","properties":{"version":{"type":"string"},"sni":{"type":"string"},"ja4":{"type":"string"},"ja4s":{"type":"string"},"ja3":{"type":"object","properties":{"hash":{"type":"string"}}}}}}}}}},"BatchIngestPayload":{"type":"object","required":["records"],"properties":{"format":{"type":"string","enum":["json","csv","ndjson"],"default":"json"},"source":{"type":"string","description":"Batch source identifier","example":"my-scanner"},"deduplicate":{"type":"boolean","default":false,"description":"Skip duplicate fingerprints within the batch"},"records":{"type":"array","description":"Array of observation records","items":{"type":"object","properties":{"ts":{"type":"integer","description":"Unix timestamp in milliseconds"},"ja4":{"type":"string"},"ja4h":{"type":"string"},"ja4s":{"type":"string"},"ja4t":{"type":"string"},"ja4x":{"type":"string"},"ja4ssh":{"type":"string"},"src_ip":{"type":"string"},"dst_ip":{"type":"string"},"sensor":{"type":"string"},"host":{"type":"string"},"path":{"type":"string"}}}}}}}}}