{"components":{"responses":{},"schemas":{"Attacker":{"description":"An attacker on a killmail","properties":{"alliance_id":{"description":"Alliance ID","nullable":true,"type":"integer"},"alliance_name":{"description":"Alliance name","nullable":true,"type":"string"},"character_id":{"description":"Character ID","type":"integer"},"character_name":{"description":"Character name","type":"string"},"corporation_id":{"description":"Corporation ID","type":"integer"},"corporation_name":{"description":"Corporation name","type":"string"},"damage_done":{"description":"Damage dealt","type":"integer"},"final_blow":{"description":"Dealt final blow","type":"boolean"},"ship_name":{"description":"Ship name","type":"string"},"ship_type_id":{"description":"Ship type ID","type":"integer"},"weapon_name":{"description":"Weapon name","type":"string"},"weapon_type_id":{"description":"Weapon type ID","type":"integer"}},"required":["damage_done","final_blow"],"title":"Attacker","type":"object"},"BulkKillsResponse":{"description":"Response containing kills for multiple systems","example":{"systems_kills":{"30000142":[{"attackers":[{"character_id":90379338}],"kill_time":"2024-01-01T12:00:00Z","killmail_id":123456789,"system_id":30000142,"victim":{"character_id":95465499},"zkb":{"totalValue":100000000}}]},"timestamp":"2024-01-01T12:00:00Z"},"properties":{"systems_kills":{"additionalProperties":{"items":{"$ref":"#/components/schemas/Killmail"},"type":"array"},"description":"Map of system IDs to their kill lists","type":"object"},"timestamp":{"description":"ISO8601 timestamp of the response","format":"date-time","type":"string"}},"required":["systems_kills","timestamp"],"title":"BulkKillsResponse","type":"object"},"Error":{"description":"Error response","example":{"error":{"message":"Invalid system_ids parameter","subtype":"invalid_format","type":"validation_error"}},"properties":{"error":{"properties":{"details":{"description":"Additional error details","nullable":true,"type":"object"},"message":{"description":"Error message","type":"string"},"subtype":{"description":"Error subtype","type":"string"},"type":{"description":"Error type","type":"string"}},"required":["type","message"],"type":"object"}},"required":["error"],"title":"Error","type":"object"},"HealthStatus":{"description":"Health check response","properties":{"components":{"additionalProperties":{"properties":{"message":{"nullable":true,"type":"string"},"status":{"type":"string"}},"type":"object"},"description":"Individual component health","type":"object"},"status":{"description":"Overall health status","enum":["healthy","degraded","unhealthy"],"type":"string"},"timestamp":{"format":"date-time","type":"string"}},"required":["status","components","timestamp"],"title":"HealthStatus","type":"object"},"KillCountResponse":{"description":"Response containing kill count for a system","example":{"count":42,"system_id":30000142,"timestamp":"2024-01-01T12:00:00Z"},"properties":{"count":{"description":"Total number of kills in the system","type":"integer"},"system_id":{"description":"EVE Online system ID","type":"integer"},"timestamp":{"description":"ISO8601 timestamp of the response","format":"date-time","type":"string"}},"required":["system_id","count","timestamp"],"title":"KillCountResponse","type":"object"},"Killmail":{"description":"A complete killmail record with enriched data","example":{"attackers":[{"character_id":123456789,"character_name":"Attacker Name","final_blow":true,"ship_name":"Rattlesnake","ship_type_id":17918}],"kill_time":"2024-01-15T14:30:00Z","killmail_id":123456789,"solar_system_id":30000142,"solar_system_name":"Jita","victim":{"character_id":987654321,"character_name":"Victim Name","ship_name":"Raven","ship_type_id":670}},"properties":{"attackers":{"items":{"$ref":"#/components/schemas/Attacker"},"type":"array"},"kill_time":{"description":"Time when the kill occurred","format":"date-time","type":"string"},"killmail_id":{"description":"Unique killmail ID","type":"integer"},"solar_system_id":{"description":"EVE system ID","type":"integer"},"solar_system_name":{"description":"System name","type":"string"},"victim":{"$ref":"#/components/schemas/Victim"},"zkb":{"$ref":"#/components/schemas/ZKB"}},"required":["killmail_id","kill_time","solar_system_id","victim","attackers"],"title":"Killmail","type":"object"},"KillmailResponse":{"allOf":[{"$ref":"#/components/schemas/Killmail"}],"description":"Response containing a single killmail","example":{"attackers":[{"alliance_id":99000002,"character_id":90379338,"corporation_id":98000002,"damage_done":5432,"final_blow":true,"ship_type_id":17918}],"kill_time":"2024-01-01T12:00:00Z","killmail_id":123456789,"system_id":30000142,"victim":{"alliance_id":99000001,"character_id":95465499,"corporation_id":98000001,"damage_taken":5432,"ship_type_id":670},"zkb":{"awox":false,"npc":false,"points":1,"solo":true,"totalValue":100000000}},"title":"KillmailResponse","type":"object"},"KillsResponse":{"description":"Response containing a list of killmails","properties":{"data":{"properties":{"cached":{"description":"Whether this data was served from cache","type":"boolean"},"data_fetched_at":{"description":"When the killmail data was originally fetched from zKillboard/ESI","format":"date-time","type":"string"},"kills":{"description":"List of killmails","items":{"$ref":"#/components/schemas/Killmail"},"type":"array"}},"required":["kills","data_fetched_at","cached"],"type":"object"},"response_timestamp":{"description":"When this API response was generated (useful for cache age calculation)","format":"date-time","type":"string"}},"required":["data","response_timestamp"],"title":"KillsResponse","type":"object"},"SSE Stream":{"description":"Server-Sent Events stream format","example":"event: connected\ndata: SSE stream connected\n\nevent: killmail\ndata: {\"killmail_id\": 123456789, \"kill_time\": \"2024-01-15T14:30:00Z\", ...}\nid: 123456789\n\nevent: heartbeat\ndata: {\"timestamp\": \"2024-01-15T14:30:00Z\"}\n","format":"text/event-stream","title":"SSE Stream","type":"string"},"SSEEvent":{"description":"Server-Sent Event formats","oneOf":[{"properties":{"data":{"enum":["SSE stream connected"],"type":"string"},"event":{"enum":["connected"],"type":"string"}},"type":"object"},{"properties":{"data":{"$ref":"#/components/schemas/Killmail"},"event":{"enum":["killmail"],"type":"string"},"id":{"type":"string"}},"type":"object"},{"properties":{"data":{"properties":{"timestamp":{"format":"date-time","type":"string"}},"type":"object"},"event":{"enum":["heartbeat"],"type":"string"}},"type":"object"}],"title":"SSEEvent"},"Subscription":{"description":"Webhook subscription","properties":{"callback_url":{"description":"Webhook URL","type":"string"},"character_ids":{"description":"Tracked character IDs","items":{"type":"integer"},"type":"array"},"created_at":{"format":"date-time","type":"string"},"id":{"description":"Subscription ID","type":"string"},"subscriber_id":{"description":"Subscriber identifier","type":"string"},"system_ids":{"description":"Subscribed system IDs","items":{"type":"integer"},"type":"array"}},"required":["id","subscriber_id","callback_url","created_at"],"title":"Subscription","type":"object"},"SubscriptionDeleteResponse":{"description":"Response after deleting subscriptions","example":{"data":{"message":"Successfully unsubscribed","subscriber_id":"user123"}},"properties":{"data":{"properties":{"message":{"description":"Success message","type":"string"},"subscriber_id":{"description":"ID of the unsubscribed subscriber","type":"string"}},"required":["message","subscriber_id"],"type":"object"}},"required":["data"],"title":"SubscriptionDeleteResponse","type":"object"},"SubscriptionListResponse":{"description":"Response containing a list of subscriptions","example":{"data":{"count":1,"subscriptions":[{"callback_url":"https://example.com/webhook","character_ids":[95465499],"created_at":"2024-01-01T12:00:00Z","id":"sub_123456789","subscriber_id":"user123","system_ids":[30000142,30000143],"type":"webhook","updated_at":"2024-01-01T12:00:00Z"}]}},"properties":{"data":{"properties":{"count":{"description":"Total number of subscriptions","type":"integer"},"subscriptions":{"items":{"properties":{"callback_url":{"type":"string"},"character_ids":{"items":{"type":"integer"},"type":"array"},"created_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"subscriber_id":{"type":"string"},"system_ids":{"items":{"type":"integer"},"type":"array"},"type":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"type":"array"}},"required":["subscriptions","count"],"type":"object"}},"required":["data"],"title":"SubscriptionListResponse","type":"object"},"SubscriptionResponse":{"description":"Response after creating a subscription","example":{"data":{"message":"Subscription created successfully","subscription_id":"sub_123456789"}},"properties":{"data":{"properties":{"message":{"description":"Success message","type":"string"},"subscription_id":{"description":"Unique identifier for the created subscription","type":"string"}},"required":["subscription_id","message"],"type":"object"}},"required":["data"],"title":"SubscriptionResponse","type":"object"},"SubscriptionStatsResponse":{"description":"Response containing subscription statistics","example":{"data":{"characters_tracked":89,"systems_tracked":127,"total_subscriptions":42,"unique_subscribers":15}},"properties":{"data":{"properties":{"characters_tracked":{"description":"Number of unique characters being tracked","type":"integer"},"systems_tracked":{"description":"Number of unique systems being tracked","type":"integer"},"total_subscriptions":{"description":"Total number of active subscriptions","type":"integer"},"unique_subscribers":{"description":"Number of unique subscribers","type":"integer"}},"type":"object"}},"required":["data"],"title":"SubscriptionStatsResponse","type":"object"},"Victim":{"description":"The victim of a killmail","properties":{"alliance_id":{"description":"Alliance ID","nullable":true,"type":"integer"},"alliance_name":{"description":"Alliance name","nullable":true,"type":"string"},"character_id":{"description":"Character ID","type":"integer"},"character_name":{"description":"Character name","type":"string"},"corporation_id":{"description":"Corporation ID","type":"integer"},"corporation_name":{"description":"Corporation name","type":"string"},"damage_taken":{"description":"Total damage taken","type":"integer"},"ship_name":{"description":"Ship name","type":"string"},"ship_type_id":{"description":"Ship type ID","type":"integer"}},"required":["character_id","ship_type_id","damage_taken"],"title":"Victim","type":"object"},"ZKB":{"description":"zKillboard metadata","properties":{"awox":{"description":"Friendly fire","type":"boolean"},"fitted_value":{"description":"Fitted modules value","type":"number"},"hash":{"description":"Kill hash","type":"string"},"location_id":{"description":"Location ID","type":"integer"},"npc":{"description":"NPC kill","type":"boolean"},"points":{"description":"Kill points","type":"integer"},"solo":{"description":"Solo kill","type":"boolean"},"total_value":{"description":"Total ISK value","type":"number"}},"title":"ZKB","type":"object"}}},"info":{"description":"Real-time EVE Online killmail data service.\n\nThis API provides access to killmail data from EVE Online with various integration options:\n- REST endpoints for fetching historical data\n- Server-Sent Events (SSE) for real-time streaming\n- WebSocket connections for bidirectional communication\n- Webhook subscriptions for push notifications\n\nAll killmail data is enriched with additional information from EVE's ESI API.\n","title":"Wanderer Kills API","version":"1.0.0"},"openapi":"3.0.0","paths":{"/api/v1/*path":{"delete":{"callbacks":{},"description":"Returns a 404 error for undefined API routes","operationId":"WandererKillsWeb.KillsController.not_found (3)","parameters":[],"responses":{"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not Found"}},"summary":"Handle undefined API routes","tags":[]},"get":{"callbacks":{},"description":"Returns a 404 error for undefined API routes","operationId":"WandererKillsWeb.KillsController.not_found","parameters":[],"responses":{"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not Found"}},"summary":"Handle undefined API routes","tags":[]},"patch":{"callbacks":{},"description":"Returns a 404 error for undefined API routes","operationId":"WandererKillsWeb.KillsController.not_found (5)","parameters":[],"responses":{"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not Found"}},"summary":"Handle undefined API routes","tags":[]},"post":{"callbacks":{},"description":"Returns a 404 error for undefined API routes","operationId":"WandererKillsWeb.KillsController.not_found (4)","parameters":[],"responses":{"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not Found"}},"summary":"Handle undefined API routes","tags":[]},"put":{"callbacks":{},"description":"Returns a 404 error for undefined API routes","operationId":"WandererKillsWeb.KillsController.not_found (2)","parameters":[],"responses":{"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not Found"}},"summary":"Handle undefined API routes","tags":[]}},"/api/v1/killmail/{killmail_id}":{"get":{"callbacks":{},"description":"Returns detailed information about a specific killmail","operationId":"WandererKillsWeb.KillsController.show","parameters":[{"description":"Killmail ID","example":123456789,"in":"path","name":"killmail_id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KillmailResponse"}}},"description":"Success"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid parameters"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Killmail not found"}},"summary":"Get a specific killmail","tags":[]}},"/api/v1/kills/cached/{system_id}":{"get":{"callbacks":{},"description":"Returns cached killmail data for a specific system","operationId":"WandererKillsWeb.KillsController.cached","parameters":[{"description":"EVE Online system ID","example":30000142,"in":"path","name":"system_id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KillsResponse"}}},"description":"Success"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid parameters"}},"summary":"Get cached kills for a system","tags":[]}},"/api/v1/kills/count/{system_id}":{"get":{"callbacks":{},"description":"Returns the total number of kills for a specific system","operationId":"WandererKillsWeb.KillsController.count","parameters":[{"description":"EVE Online system ID","example":30000142,"in":"path","name":"system_id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KillCountResponse"}}},"description":"Success"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid parameters"}},"summary":"Get kill count for a system","tags":[]}},"/api/v1/kills/stream":{"get":{"callbacks":{},"description":"Real-time Server-Sent Events stream of killmail data with optional filtering.\n\nThe stream will send different types of events:\n- `connected`: Initial connection confirmation\n- `killmail`: New killmail data\n- `batch`: Historical killmails (on connection)\n- `heartbeat`: Keep-alive signal (every 30 seconds)\n- `error`: Error notifications\n","operationId":"WandererKillsWeb.KillStreamController.stream","parameters":[{"description":"Comma-separated list of system IDs to filter","example":"30000142,30000144","in":"query","name":"system_ids","required":false,"schema":{"type":"string"}},{"description":"Comma-separated character IDs to track as victim/attacker","example":"123456789,987654321","in":"query","name":"character_ids","required":false,"schema":{"type":"string"}},{"description":"Minimum ISK value threshold for killmails","example":100000000,"in":"query","name":"min_value","required":false,"schema":{"type":"number"}}],"responses":{"200":{"content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/SSE Stream"}}},"description":"SSE stream started"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid parameters"}},"summary":"Stream killmail events via SSE","tags":[]}},"/api/v1/kills/stream/cleanup":{"get":{"callbacks":{},"description":"Debug endpoint to cleanup dead SSE connections","operationId":"WandererKillsWeb.KillStreamController.cleanup","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"message":{"type":"string"}},"type":"object"}}},"description":"Success"}},"summary":"Cleanup SSE connections (Debug)","tags":[]}},"/api/v1/kills/stream/enhanced":{"get":{"callbacks":{},"description":"Enhanced Server-Sent Events stream with support for historical data preloading.\n\nPreloading behavior:\n- If `character_ids` and `preload_days` are specified: loads historical character killmails\n- If `system_ids` and `preload_days` are specified: loads historical system killmails\n- Character preloading takes precedence if both character_ids and system_ids are provided\n\nEvent types:\n- `connected`: Initial connection confirmation\n- `batch`: Historical killmail batch (when preload_days > 0)\n- `transition`: Marks switch from historical to real-time mode\n- `killmail`: Real-time killmail updates\n- `heartbeat`: Keep-alive with mode indicator\n- `error`: Error notifications\n","operationId":"WandererKillsWeb.EnhancedKillStreamController.stream","parameters":[{"description":"Comma-separated list of system IDs to filter","example":"30000142,30000144","in":"query","name":"system_ids","required":false,"schema":{"type":"string"}},{"description":"Comma-separated character IDs to track as victim/attacker","example":"123456789,987654321","in":"query","name":"character_ids","required":false,"schema":{"type":"string"}},{"description":"Minimum ISK value threshold for killmails","example":100000000,"in":"query","name":"min_value","required":false,"schema":{"type":"number"}},{"description":"Number of days of historical data to preload (max 90)","example":90,"in":"query","name":"preload_days","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/SSE Stream"}}},"description":"SSE stream started"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid parameters"}},"summary":"Enhanced SSE stream with character preloading","tags":[]}},"/api/v1/kills/stream/stats":{"get":{"callbacks":{},"description":"Debug endpoint to get SSE connection statistics","operationId":"WandererKillsWeb.KillStreamController.stats","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"message":{"type":"string"},"pubsub_name":{"type":"string"}},"type":"object"}}},"description":"Success"}},"summary":"Get SSE statistics (Debug)","tags":[]}},"/api/v1/kills/stream/test":{"get":{"callbacks":{},"description":"Debug endpoint to test PubSub delivery to SSE connections","operationId":"WandererKillsWeb.KillStreamController.test_broadcast","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"killmail_id":{"type":"integer"},"message":{"type":"string"},"topics":{"items":{"type":"string"},"type":"array"}},"type":"object"}}},"description":"Success"}},"summary":"Test SSE broadcast (Debug)","tags":[]}},"/api/v1/kills/system/{system_id}":{"get":{"callbacks":{},"description":"Fetches killmail data for a specific system with optional time filtering","operationId":"WandererKillsWeb.KillsController.list","parameters":[{"description":"EVE Online system ID","example":30000142,"in":"path","name":"system_id","required":true,"schema":{"type":"integer"}},{"description":"Fetch kills from the last N hours (default: 24)","example":24,"in":"query","name":"since_hours","required":false,"schema":{"type":"integer"}},{"description":"Maximum number of kills to return","example":100,"in":"query","name":"limit","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KillsResponse"}}},"description":"Success"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid parameters"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Server error"}},"summary":"List kills for a system","tags":[]}},"/api/v1/kills/systems":{"post":{"callbacks":{},"description":"Fetches killmail data for multiple systems with optional time filtering","operationId":"WandererKillsWeb.KillsController.bulk","parameters":[],"requestBody":{"content":{"application/json":{"schema":{"properties":{"limit":{"description":"Maximum number of kills to return per system","example":100,"type":"integer"},"since_hours":{"description":"Fetch kills from the last N hours","example":24,"type":"integer"},"system_ids":{"description":"List of EVE Online system IDs","example":[30000142,30000144],"items":{"type":"integer"},"type":"array"}},"required":["system_ids"],"type":"object"}}},"description":"Request body","required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkKillsResponse"}}},"description":"Success"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid parameters"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Server error"}},"summary":"Fetch kills for multiple systems","tags":[]}},"/api/v1/subscriptions":{"get":{"callbacks":{},"description":"Returns a list of all active webhook subscriptions","operationId":"WandererKillsWeb.SubscriptionController.index","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionListResponse"}}},"description":"Success"}},"summary":"List all subscriptions","tags":[]},"post":{"callbacks":{},"description":"Create a new webhook subscription for killmail notifications","operationId":"WandererKillsWeb.SubscriptionController.create","parameters":[],"requestBody":{"content":{"application/json":{"schema":{"properties":{"callback_url":{"description":"HTTP/HTTPS URL to receive webhook notifications","example":"https://example.com/webhook","format":"uri","type":"string"},"character_ids":{"description":"List of EVE Online character IDs","example":[95465499,90379338],"items":{"type":"integer"},"type":"array"},"subscriber_id":{"description":"Unique identifier for the subscriber","example":"user123","type":"string"},"system_ids":{"description":"List of EVE Online system IDs","example":[30000142,30000143],"items":{"type":"integer"},"type":"array"}},"required":["subscriber_id","callback_url"],"type":"object"}}},"description":"Request body","required":false},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}},"description":"Success"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid parameters"}},"summary":"Create webhook subscription","tags":[]}},"/api/v1/subscriptions/stats":{"get":{"callbacks":{},"description":"Returns aggregate information and statistics about subscriptions","operationId":"WandererKillsWeb.SubscriptionController.stats","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionStatsResponse"}}},"description":"Success"}},"summary":"Get subscription statistics","tags":[]}},"/api/v1/subscriptions/{subscriber_id}":{"delete":{"callbacks":{},"description":"Delete all subscriptions for a specific subscriber","operationId":"WandererKillsWeb.SubscriptionController.delete","parameters":[{"description":"Subscriber ID to unsubscribe","example":"user123","in":"path","name":"subscriber_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionDeleteResponse"}}},"description":"Success"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Partial failure"}},"summary":"Delete subscriber subscriptions","tags":[]}}},"security":[],"servers":[{"description":"Development server","url":"http://localhost:4004","variables":{}}],"tags":[]}