Documentation
Getting Started
Core Features
Advanced Usage
Resources
SANS.AI Documentation
Welcome to the official documentation for SANS.AI (Smart Airport Navigation System), the comprehensive AI-powered platform designed to optimize airport operations.
Note About Documentation
This documentation covers SANS.AI version 2.5.0 and later.
What is SANS.AI?
SANS.AI is a state-of-the-art software platform that leverages artificial intelligence and real-time data analytics to provide comprehensive airport management solutions. The system is designed to enhance operational efficiency, improve safety, and optimize resource allocation throughout airport facilities.
Key Capabilities
- Real-time Flight Tracking: Monitor all aspects of flight operations with comprehensive dashboards
- Predictive Analytics: Anticipate operational challenges with AI-powered predictions
- Enhanced Safety Monitoring: Improve airport safety through automated monitoring systems
- LiDAR Passenger Flow Analysis: Track and optimize passenger movements throughout terminals
- Resource Optimization: Maximize efficiency with intelligent gate assignments and resource allocation
- Intelligent Notifications: Stay informed with automated alerts and recommendations
System Architecture
SANS.AI is built on a modular architecture that scales from a single regional airport to a major international hub without any change on your side. The core components include:
- Data Collection Layer: Integrates with flight systems, weather data, LiDAR sensors, and various other data sources
- AI Processing Engine: Advanced proprietary AI that analyzes data in real-time
- Insight Delivery System: Provides actionable recommendations and visualizations
- RESTful API: Allows for seamless integration with existing airport systems
- Security Framework: Ensures data protection and controlled access to sensitive information
There is nothing to install. SANS.AI runs as a managed service, reached through the dashboard in a browser and through the API from the systems you already operate. Your team is working in it the day the account is created, not the quarter after a procurement cycle.
Why we run it
Prediction accuracy depends on models that retrain against live operational data, and on a platform that stays current with the data sources feeding it. Running one platform lets us push that work to every customer continuously rather than shipping it as an upgrade you have to schedule. You get the accuracy without carrying the operational burden that produces it.
What you need
| Requirement | Detail |
|---|---|
| Browser | Any current version of Chrome, Edge, Firefox or Safari. The dashboard works on a phone at the gate as well as a desk |
| Network | Outbound HTTPS to www.sans-ai.tech. No inbound access to your network is required |
| Data sources | Read access to the operational systems you want reflected, typically AODB, flight feeds and weather |
| Identity | Optional single sign-on against your existing provider |
| LiDAR | Only if you enable passenger flow analysis. See the prerequisites below |
LiDAR hardware prerequisites
The LiDAR passenger flow module integrates with sensing infrastructure that you already operate in your terminals. Kquika does not supply LiDAR hardware. If you plan to enable this module, see the LiDAR Integration section for the prerequisites your installation must meet.
Onboarding
Getting live is a sequence of decisions rather than an installation. Your implementation contact works through it with you.
| Step | What happens | Who leads |
|---|---|---|
| Account and users | Your company is provisioned, the first administrator is created, and roles are mapped to your teams | Kquika |
| Airports and terminals | Your airports, terminals, gates and stands are configured to match the physical layout | Together |
| Data connections | Read connections to your operational systems are established and validated against live traffic | Together |
| Model training | Models train on your historical data. Until they have enough, prediction endpoints return a clear empty result rather than a guess | Kquika |
| Notifications | Alert thresholds, delivery channels and escalation paths are set per role | You |
| API credentials | Keys or OAuth clients are issued for the systems that will integrate | You |
Your first API call
Create a key in the dashboard under Settings, then confirm it works:
curl "https://www.sans-ai.tech/api/v1/flights/live?airport=LHR" \
-H "X-API-Key: $SANSAI_API_KEY"
From there, the API Reference covers every endpoint with a working example, and the Python and TypeScript clients handle authentication, retries and rate limits for you.
Your data
Your operational data is yours. It is encrypted in transit and at rest, isolated from every other customer on the platform by design rather than by policy, and backed up continuously. Retention follows your policy, and you can export a full copy whenever you want one.
Where a regulator or your own compliance team asks who accessed a record and when, the audit trail already holds the answer.
The SANS.AI dashboard provides a comprehensive view of your airport operations and serves as the main interface for system interaction. This section outlines the key components and functionality of the dashboard.
Dashboard Layout
The dashboard is organized into several key sections:
- Navigation Bar: Access different modules and system functions
- Overview Panel: Key metrics and status indicators for immediate situational awareness
- Flight Status: Real-time information on all flights
- Terminal Status: Passenger flow and terminal utilization metrics
- Resource Allocation: Gate assignments and ground resource status
- Weather Conditions: Current and forecasted weather affecting operations
- Alerts Panel: Notifications requiring attention
Each user can customize their dashboard view based on their role and preferences using the Dashboard Customization feature.
Navigation
The main navigation menu provides access to the following modules:
- Dashboard: Main overview screen
- Flights: Detailed flight tracking and management
- Terminal: Passenger flow analysis and terminal operations
- Resources: Gate management and resource allocation
- Safety: Safety monitoring and alerts
- Analytics: Historical data analysis and reports
- Settings: System configuration and user preferences
User Interface Elements
The dashboard incorporates various UI elements designed for efficient airport operations management:
- Interactive Maps: Visual representation of terminals, gates, and runways
- Real-time Charts: Dynamic visualizations of operational metrics
- Status Cards: At-a-glance information about specific operational aspects
- Alert Notifications: Color-coded alerts for various severity levels
- Action Buttons: Quick access to common tasks and operations
- Search Functionality: Rapidly locate specific flights, gates, or resources
Personalization
Users can personalize their dashboard experience through several customization options:
- Layout Configuration: Arrange dashboard components
- Widget Selection: Add or remove information widgets
- Saved Views: Create and switch between role-specific layouts
- Color Themes: Choose between light and dark modes
- Notification Preferences: Configure alert thresholds and delivery methods
User-Specific Views
Dashboard settings are saved per user, allowing each team member to configure their view according to their specific role and requirements.
The Flight Tracking module is a core component of SANS.AI that provides comprehensive real-time monitoring and management of all flight operations. This sophisticated system integrates with existing flight data systems while adding powerful AI-driven analytics and visualization capabilities.
Flight Data Integration
SANS.AI connects with multiple flight data sources to provide a complete operational picture:
- ADS-B Data Feeds: Real-time aircraft positions and telemetry
- Airport Operational Database (AODB): Scheduled flight information
- Air Traffic Control Systems: Runway assignments and approach data
- Airline Systems: Gate assignments, aircraft details, and boarding status
- Weather Services: Current and forecasted conditions affecting flights
The system normalizes and correlates data from these disparate sources to create a single, unified view of flight operations.
Flight Monitoring Interface
The flight monitoring dashboard provides multiple views to accommodate different operational needs:
- Map View: Interactive spatial representation of flights and their status
- Timeline View: Chronological visualization of arrivals and departures
- List View: Tabular representation with detailed flight information
- Gate View: Gate-centric display showing occupancy and scheduling
- Runway View: Runway utilization and sequencing information
View Synchronization
All views are synchronized, allowing operators to switch between perspectives while maintaining focus on specific flights or operational areas.
Flight Status Tracking
SANS.AI tracks flights through their complete lifecycle, from scheduling to completion, with detailed status information at each stage:
| Status | Description | Key Metrics Tracked |
|---|---|---|
| Scheduled | Flight is planned but not yet active | Scheduled times, gate assignments, expected passenger load |
| Boarding | Passengers are boarding the aircraft | Boarding progress, estimated completion time, passenger exceptions |
| Taxiing Out | Aircraft is moving from gate to runway | Ground position, estimated runway arrival, taxiway congestion |
| Departed | Aircraft has taken off | Actual departure time, departure delay, runway used |
| En Route | Aircraft is in flight to destination | Current position, altitude, speed, estimated arrival time |
| Approaching | Aircraft is approaching the destination airport | Approach path, assigned runway, weather conditions |
| Landed | Aircraft has landed and is taxiing to gate | Actual arrival time, arrival delay, assigned gate |
| At Gate | Aircraft is parked at the gate | Gate arrival time, turnaround clock, deplaning status |
Anomaly Detection
The Flight Tracking module employs advanced AI algorithms to detect anomalies in flight operations:
- Deviation Detection: Identifying flights that deviate from expected patterns
- Conflict Prediction: Foreseeing potential conflicts in runway usage or gate assignments
- Fuel Issues: Detecting abnormal fuel consumption or low fuel situations
- Schedule Disruptions: Identifying cascading effects of delays or cancellations
- Unusual Flight Parameters: Flagging abnormal altitude, speed, or position data
When anomalies are detected, the system generates alerts with appropriate severity levels and recommended actions.
Operational Analytics
Beyond real-time tracking, the module provides operational analytics to help optimize flight operations:
- On-Time Performance: Analysis of departure and arrival punctuality
- Delay Patterns: Identification of recurring delay causes and trends
- Runway Utilization: Metrics on runway usage efficiency and capacity
- Gate Turnaround: Analysis of aircraft turnaround times by gate, airline, and aircraft type
- Weather Impact: Correlation between weather conditions and operational performance
Flight Search and Filtering
SANS.AI provides powerful search and filtering capabilities to quickly locate specific flights based on various criteria:
-- Example of advanced flight filtering syntax
FILTER flights WHERE
origin = 'JFK' AND
status = 'En Route' AND
arrival_time BETWEEN '14:00' AND '16:00' AND
aircraft_type IN ('B738', 'A320', 'E190')
ORDER BY arrival_time ASC
The system also supports natural language queries for users who prefer a more conversational interface:
Example natural language queries:
- "Show me all delayed United flights from Chicago"
- "Which flights are arriving at Terminal A in the next hour?"
- "List all flights with more than 30 minutes taxi time"
Historical Data Access
The Flight Tracking module maintains a comprehensive history of all flight operations, allowing users to:
- Review Past Operations: Examine historical flight data for analysis or investigation
- Compare Periods: Analyze performance across different time periods
- Track Trends: Identify long-term patterns in operational performance
- Generate Reports: Create customized reports for management or regulatory purposes
Historical data can be accessed through the same interface used for real-time tracking, with additional filtering options for time periods and comparison features.
The Predictive Analytics module is one of SANS.AI's most powerful features, leveraging advanced AI technology to anticipate operational challenges before they occur. This module transforms historical and real-time data into actionable forecasts that empower proactive decision-making.
Prediction Capabilities
SANS.AI provides predictive analytics across multiple operational domains:
- Delay Prediction: Forecasting flight delays based on multiple factors
- Congestion Forecasting: Predicting terminal and runway congestion
- Weather Impact Assessment: Anticipating operational impacts of forecasted weather
- Resource Needs: Projecting staffing and equipment requirements
- Passenger Flows: Forecasting passenger volume and movement patterns
Prediction Models
The system employs multiple proprietary AI engines optimized for different prediction tasks:
| AI Engine | Primary Applications | Key Benefits |
|---|---|---|
| SANS ForecastIQâ„¢ | Delay prediction, Arrival/departure forecasting, Demand planning | Multi-algorithm ensemble for industry-leading prediction accuracy |
| SANS ResourceMaxâ„¢ | Gate assignments, Staff scheduling, Resource optimization | Intelligent optimization across multiple constraints simultaneously |
| SANS PathMasterâ„¢ | Passenger routing, Taxi path optimization, Wayfinding | Dynamic navigation with real-time congestion awareness |
| SANS PinPointâ„¢ | Asset tracking, Passenger location, Indoor positioning | High-precision positioning combining multiple sensor technologies |
| SANS PersonaLensâ„¢ | Personalized recommendations, Service suggestions, Retail targeting | Context-aware recommendations based on passenger profiles and behavior |
These AI engines are continuously refined using the latest operational data to ensure optimal predictive performance.
Custom AI Solutions
Enterprise tier customers can work with our AI team to develop custom prediction engines specific to their operational environment and unique challenges.
Model status and what accuracy means
Only a model with status active can serve a prediction. Its accuracy is measured against held-out data during training and is never estimated. Where a model has not been trained, or its training produced no score, accuracy is null rather than a placeholder. A status of untrained, failed or simulated means no trained artifact exists, and calling that model returns 404 with NO_DATA_AVAILABLE.
Prediction Accuracy and Confidence
All predictions include accuracy metrics and confidence levels to help operators assess reliability:
- Confidence Score: Percentage indicating prediction reliability
- Error Margins: Expected variation range for numerical predictions
- Contributing Factors: Key variables influencing the prediction
- Historical Accuracy: Performance metrics for similar past predictions
Visualization and Interpretation
Predictive insights are presented through intuitive visualizations designed for operational use:
- Heat Maps: Visual representation of predicted congestion areas
- Probability Distributions: Range of potential outcomes with likelihood
- Time-Series Forecasts: Projected trends over upcoming hours/days
- Decision Trees: Visual explanation of prediction logic for key decisions
- What-If Scenario Modeling: Interactive tools to test alternative actions
Actionable Recommendations
Beyond predictions, SANS.AI provides specific recommendations to address forecasted challenges:
- Staffing Adjustments: Personnel reallocation based on predicted demand
- Gate Reassignments: Optimized gate changes to prevent congestion
- Runway Configuration Changes: Proactive adjustment for weather conditions
- Resource Prioritization: Focus areas for equipment and staff resources
- Passenger Communication: Targeted messaging for potential disruptions
Custom Prediction Scenarios
Operators can create custom prediction scenarios to evaluate potential operational changes:
# Example of a custom prediction scenario configuration
scenario = Prediction.create_scenario({
'name': 'Weather Impact Assessment',
'base_conditions': {
'time_range': ('2023-05-15T14:00:00', '2023-05-15T22:00:00'),
'runways_active': ['18L', '18R', '17R'],
'terminal_capacity': 'standard'
},
'variable_factors': {
'weather': {
'wind_direction': 180, # degrees
'wind_speed': 25, # knots
'visibility': 3, # miles
'precipitation': 0.2 # inches/hour
}
},
'output_metrics': [
'runway_throughput',
'departure_delays',
'arrival_delays',
'gate_congestion'
]
})
results = scenario.run()
scenario.visualize()
Prediction API
For integration with external systems, SANS.AI provides a REST API to access predictions programmatically:
{
"request": {
"prediction_type": "delay_forecast",
"parameters": {
"flight_ids": ["UA123", "DL456", "AA789"],
"prediction_window": "6h",
"confidence_threshold": 70
}
},
"response": {
"predictions": [
{
"flight_id": "UA123",
"scheduled_departure": "2023-05-15T15:30:00Z",
"predicted_departure": "2023-05-15T16:15:00Z",
"delay_minutes": 45,
"confidence": 85,
"contributing_factors": [
{"factor": "weather", "weight": 0.6},
{"factor": "inbound_aircraft_delay", "weight": 0.3},
{"factor": "terminal_congestion", "weight": 0.1}
]
},
// Additional predictions...
],
"timestamp": "2023-05-15T12:30:00Z"
}
}
Continuous AI Improvement
The SANS.AI prediction system continuously improves through several mechanisms:
- Automatic Updates: Regular AI engine refinements incorporating new operational data
- Accuracy Feedback: Actual outcomes are compared to predictions to improve accuracy
- Cross-Airport Learning: Insights from similar airports are applied where relevant
- Smart Data Analysis: Ongoing development of new predictive indicators
- Performance Monitoring: Regular benchmarking of prediction accuracy
AI performance statistics and accuracy metrics are available in the Analytics section of the dashboard.
SANS.AI incorporates comprehensive safety monitoring capabilities designed to enhance operational safety through automated detection, risk assessment, and proactive alerting. This module focuses on identifying and preventing potential safety incidents across all airport operations.
Safety Monitoring Systems
The safety module integrates multiple monitoring systems to provide full operational coverage:
- Runway Monitoring: Detection of runway incursions and traffic conflicts
- Spacing observations: Recorded spacing between movements, compared against your local pattern
- Ground Movement: Tracking of vehicle and aircraft movements in ground areas
- Weather Safety: Assessment of weather-related safety risks
- Terminal Safety: Monitoring of passenger flow and terminal safety conditions
Important Safety Disclaimer
SANS.AI is supplementary safety monitoring. It is not a safety management system of record, it does not perform any air traffic control function, and it is not certified to a software assurance level under ED-109A or DO-278A. Nothing here replaces your primary safety systems, your SMS, or human oversight. Use it to see patterns earlier, and record decisions against the system your regulator already recognizes.
Runway Incursion Detection Support
The runway module reviews movement data for patterns consistent with an incursion and raises them for an operator to act on. It does not issue clearances, does not control movement, and is not a substitute for the surface movement systems your tower already runs.
- Movement data: Whatever surface and flight movement feeds you already connect, combined into one view
- Pattern Recognition: Identifying unusual movement patterns that may indicate a risk
- Early flags: Raising a pattern for review before it develops, with the confidence behind it
- Taxiway Monitoring: Tracking aircraft and vehicle positions on taxiways adjacent to runways
- Runway Status Tracking: Real-time monitoring of runway occupancy and clearance status
A flagged condition raises a high-priority alert to the operators you nominate. Every alert records the model and version that produced it, the confidence, and who acknowledged it, so the decision trail survives the shift.
Spacing Observations
The platform observes recorded spacing between movements and flags where it departs from the pattern normal for that operation. This is an observation for planning and post-operations review. Separation assurance is an air traffic control function and remains entirely with your ANSP.
| Operation Phase | Monitoring Capabilities | Alert Triggers |
|---|---|---|
| Approach | Approach sequence, spacing between aircraft | Spacing tighter than the local pattern, approach speed outside the usual band |
| Landing | Runway occupancy, exit taxiway monitoring | Runway not clear, late exit |
| Ground Movement | Taxiway congestion, crossing conflicts | Potential path conflicts, unusual stopping patterns |
| Departure | Takeoff sequence, departure spacing | Spacing tighter than the local pattern, sequence departing from the plan |
Evidence behind every alert
Each alert carries the record of how it came about. This is what makes an alert reviewable months later, and it is recorded from the moment the module is enabled rather than gathered when someone asks.
| Recorded | Why it matters |
|---|---|
| Detection method | Whether a rule or a model raised it, so the two can be assessed separately |
| Turnaround, where there is one | Links an alert raised on the ramp back to the turn it came from |
| Model name and version | A model that changes behavior is traceable to the release that changed it |
| Confidence | Distinguishes a marginal flag from a strong one when reviewing a batch |
| Input reference | Points back to the movement data the flag was drawn from |
| Who acknowledged it, and when | Establishes that a human saw it and how long that took |
| Disposition and note | Records whether it was actioned, stood down, or judged a false positive |
Those last two are the ones that matter most. A flag nobody acted on and a flag correctly stood down look identical without them, and the difference is the whole question when reviewing whether the module is helping.
Acknowledging an alert is a single call, from the dashboard or the API:
sansai.acknowledge_alert(
alert_id,
disposition="false_positive",
note="Vehicle had clearance, radio log confirms",
)
The first acknowledgement stamps who saw it and when, and the response reports how long that took. A disposition of stood_down, false_positive or duplicate also resolves the alert. actioned and referred leave it open, because the work is.
Demonstration content is marked, not mixed in
A new account with no safety data sees sample alerts so the module is not an empty screen. Those carry detection_method: "sample", are never written to your safety records, cannot be dispositioned, and are excluded from every review query. Nothing invented ever enters the evidence trail.
Assurance, stated plainly
We are working toward a defensible position for this module against the software assurance guidance that applies to ground systems supporting aircraft operations, ED-109A and DO-278A. That is a multi year effort and it is not finished. Until it is, treat the module as supplementary monitoring and say so to your own safety department. We would rather tell you where we are than let a procurement question find it.
The reason evidence is recorded now, years before any assurance case is complete, is that operational history cannot be created retrospectively. A case built on eighteen months of recorded detections, dispositions and outcomes is a different argument from one built on a description of intent. The only way to have that history later is to start keeping it today.
Anomaly Detection System
A core component of the safety module is the anomaly detection system that identifies unusual patterns that may indicate safety concerns:
- Behavior Analysis: Identifying aircraft movements that deviate from normal patterns
- Response timing: Tracking how long flagged conditions go unacknowledged
- System Status Anomalies: Identifying unusual status indications from aircraft or ground systems
- Environmental Anomalies: Detecting unexpected weather patterns or environmental conditions
- Temporal Anomalies: Identifying unusual timing or sequencing in operations
The anomaly detection system employs multiple AI algorithms including isolation forests, autoencoders, and time-series anomaly detection to identify potential safety concerns.
Risk Assessment Framework
All detected safety concerns are evaluated through a comprehensive risk assessment framework:
# Example of the risk assessment calculation
def calculate_risk_score(event):
# Base factors
severity = determine_severity(event) # 1-10 scale
probability = determine_probability(event) # 0.0-1.0
# Contextual factors
time_factor = 1.0
if event.is_peak_hours():
time_factor = 1.5
weather_factor = 1.0
if event.has_adverse_weather():
weather_factor = 1.3
visibility_factor = 1.0
if event.visibility_below(3): # miles
visibility_factor = 1.2
# Calculate composite risk score
risk_score = (severity * probability) * time_factor * weather_factor * visibility_factor
# Normalize to 0-100 scale
normalized_score = min(100, risk_score * 10)
return {
'score': normalized_score,
'severity': severity,
'probability': probability,
'contributing_factors': {
'time': time_factor,
'weather': weather_factor,
'visibility': visibility_factor
}
}
Risk scores determine alert severity, notification routing, and recommended response actions.
Safety Alerts and Notifications
The safety module provides multi-level alerting based on the severity and urgency of detected issues:
- Critical Alerts: Immediate notification for high-risk situations requiring urgent action
- Warning Alerts: Notification of developing situations that may require intervention
- Advisory Notices: Information about conditions that warrant attention or monitoring
- System Alerts: Notification of safety monitoring system status or performance issues
Alerts can be delivered through multiple channels including dashboard notifications, mobile alerts, email, SMS, and integration with airport announcement systems.
Safety Analysis and Reporting
Beyond real-time monitoring, the safety module provides comprehensive analysis and reporting capabilities:
- Safety Trend Analysis: Identification of patterns in safety incidents and near-misses
- Risk Hotspot Mapping: Visual representation of high-risk areas and times
- Causal Factor Analysis: Identification of common contributing factors in safety events
- Compliance Reporting: Automated generation of safety reports for regulatory purposes
- Safety Performance Metrics: Tracking of key safety performance indicators over time
These analytical capabilities help airports identify systemic safety issues and implement targeted improvements to enhance overall safety performance.
SANS.AI's LiDAR integration module connects to light detection and ranging sensing already deployed in your terminals and turns its output into passenger flow analysis and terminal optimization insight. The module is a software integration layer. It does not include, replace or require sensing hardware supplied by Kquika.
LiDAR Hardware Prerequisites
The module reads from sensing equipment installed in your terminal areas. That equipment is procured, installed, owned, calibrated and operated by you or your chosen contractor. For the integration to work, the following need to be in place:
- LiDAR Sensors: High-resolution 3D LiDAR units (see the appendix for models we have validated against)
- Mounting Infrastructure: Ceiling or wall mounts at strategic coverage locations
- Edge Processing Units: Local processing hardware for preliminary data analysis, which remains on your network
- Network Infrastructure: High-bandwidth, low-latency connectivity from your edge units to the SANS.AI platform
- Power Supply: Reliable power distribution with backup capabilities
If you ask us to, our implementation team can carry out a site assessment and contribute to installation planning so that sensor placement and coverage suit the analytics you want to run. Procurement, physical installation, calibration, maintenance and day-to-day operation of the equipment stay with you throughout.
Who Owns What
Kquika does not manufacture, sell, own or operate LiDAR sensors. You own and run the sensing layer, and you decide where sensors go, what areas they cover and how long any raw data held on your own edge equipment is kept. SANS.AI receives the processed output of that equipment and interprets it. Because you operate the sensors, responsibility for passenger signage, notices and any data protection impact assessment covering the sensing itself also sits with you.
Privacy Compliance
The integration is designed for privacy compliance. It processes anonymous point-cloud data describing shape and position over time, and does not capture or store facial features, gait signatures or any other personally identifiable information, making it suitable for deployment in privacy-sensitive environments. See our Privacy Policy for how this data is handled.
When no sensor is reporting
Passenger counts, bottlenecks and congestion forecasts are computed from stored sensor readings. Where no sensor in a terminal has reported inside the window, the response carries measured: false with a reason and empty values, rather than an estimate. A blank panel means no data arrived, not that the terminal is empty.
Passenger Flow Monitoring
The LiDAR system provides comprehensive passenger flow insights:
- Real-time Density Tracking: Precise measurement of passenger density across terminal areas
- Movement Paths: Analysis of common movement patterns and flow dynamics
- Dwell Time Analysis: Measurement of time spent in different terminal zones
- Queue Monitoring: Real-time tracking of queue lengths and wait times
- Bottleneck Detection: Identification of congestion points and flow constraints
These insights are visualized through intuitive heatmaps, flow diagrams, and analytics dashboards designed for operational use.
Terminal Optimization
Based on LiDAR data, SANS.AI provides actionable insights for terminal optimization:
- Staff Allocation: Data-driven recommendations for personnel placement
- Facility Layout: Insights to optimize terminal configuration and signage
- Service Point Placement: Optimal locations for information desks, kiosks, and amenities
- Processing Capacity: Recommendations for security and check-in capacity adjustments
- Retail Insights: Foot traffic analysis for commercial area optimization
LiDAR Data Visualization
The LiDAR module provides multiple visualization options to represent passenger flow data:
- Density Heatmaps: Color-coded visualizations of passenger density
- Flow Vectors: Directional indicators showing movement patterns
- 3D Terminal Models: Three-dimensional representations with overlaid analytics
- Time-lapse Visualizations: Temporal analysis of changing flow patterns
- Predictive Visualizations: Forecasted passenger flows based on real-time data
Integration with Other Modules
The LiDAR module integrates with other SANS.AI components to provide enhanced functionality:
| Module | Integration Points | Enhanced Capabilities |
|---|---|---|
| Predictive Analytics | Flow data feeds prediction models | More accurate congestion forecasts, enhanced resource planning |
| Safety Features | Anomalous crowd behavior detection | Early warning of safety risks, social distancing monitoring |
| Resource Optimization | Real-time passenger distribution data | Dynamic staff allocation, gate assignment optimization |
| Notifications | Congestion and bottleneck triggers | Automated alerts for emerging passenger flow issues |
Data Management and Retention
SANS.AI handles LiDAR data according to configurable data management policies:
- Local Pre-processing: Raw sensor output is processed on your own edge units before anything reaches the platform, and that raw data stays under your control
- Real-time Processing: Live data is processed in real-time for immediate insights
- Aggregated Storage: Historical data is stored in anonymized, aggregated format
- Retention Policies: Configurable data retention periods to meet organizational and regulatory requirements
- Access Controls: Role-based access to ensure appropriate data usage
- Privacy Safeguards: Technical measures to prevent individual identification
All data processing complies with relevant privacy regulations and industry best practices.
Performance Metrics
The LiDAR system provides key performance indicators to measure operational efficiency:
- Processing Throughput: Passengers processed per hour at key checkpoints
- Queue Wait Times: Average and maximum wait times by location and time
- Space Utilization: Passenger density relative to available space
- Flow Efficiency: Speed and smoothness of passenger movements through the terminal
- Service Point Performance: Utilization and efficiency of service locations
These metrics are tracked over time to identify trends and measure the impact of operational changes.
The Resource Optimization module helps airports maximize operational efficiency through intelligent allocation and management of gates, ground equipment, and personnel. This module uses advanced algorithms to optimize resource utilization while maintaining service levels and operational resilience.
Gate Management
SANS.AI provides sophisticated gate assignment and management capabilities:
- Intelligent Gate Assignment: Optimized allocation based on multiple factors
- Real-time Reassignment: Dynamic reallocation in response to operational changes
- Connection Optimization: Minimizing connection distances for passengers
- Utilization Balancing: Distributing usage to prevent congestion
- Aircraft Compatibility: Ensuring appropriate gate sizing and equipment
The gate optimization algorithm considers over 30 different factors to create an optimal assignment plan, including aircraft type, passenger connections, airline preferences, and historical performance.
Optimization Parameters
The resource optimization engine can be configured to prioritize different operational goals:
| Optimization Goal | Description | Primary Applications |
|---|---|---|
| Passenger Experience | Minimizing walking distances and connection times | Hub airports with high transfer volumes |
| Operational Efficiency | Maximizing throughput and resource utilization | High-volume airports with capacity constraints |
| Cost Reduction | Minimizing resource requirements and operational costs | Airports focused on operational cost management |
| Airline Preferences | Prioritizing airline-specific requirements and agreements | Airports with strong airline partnerships or dominant carriers |
| Resilience | Maximizing ability to handle disruptions with minimal impact | Airports in regions with frequent operational challenges |
These optimization parameters can be adjusted dynamically to respond to changing operational priorities.
Ground Resource Management
Beyond gate assignments, SANS.AI optimizes the allocation and routing of ground resources:
- Ground Service Equipment: Optimized allocation and routing of GSE assets
- Baggage Handling: Efficient processing and routing of baggage
- Fueling Operations: Scheduling and optimization of aircraft fueling
- Catering Services: Coordination of food service operations
- Maintenance Resources: Allocation of maintenance equipment and personnel
The system tracks resource locations, availability, and utilization to ensure optimal allocation and reduce inefficiencies.
Personnel Optimization
SANS.AI provides data-driven insights for staff allocation and scheduling:
- Demand Forecasting: Prediction of staffing needs based on operational patterns
- Dynamic Allocation: Real-time adjustment of personnel deployment
- Skill Matching: Ensuring appropriate skill distribution across operational areas
- Work Balance: Equitable distribution of workload among teams
- Compliance Management: Adherence to work regulations and safety requirements
Integration Note
While SANS.AI provides staff optimization recommendations, it is designed to integrate with specialized workforce management systems for detailed scheduling and time tracking.
Optimization Algorithm
The resource optimization engine employs sophisticated algorithms including:
# Simplified example of optimization approach
def optimize_resources(flights, available_resources, constraints, optimization_goals):
# Initialize optimization model
model = OptimizationModel()
# Define decision variables
# For each flight and potential resource assignment
assignments = {}
for flight in flights:
for resource in available_resources[flight.required_resource_type]:
assignments[(flight.id, resource.id)] = model.add_binary_variable()
# Add constraints
# Each flight must be assigned exactly one resource
for flight in flights:
model.add_constraint(
sum(assignments[(flight.id, r.id)]
for r in available_resources[flight.required_resource_type]) == 1
)
# Resources can't be double-booked
for resource_type in available_resources:
for resource in available_resources[resource_type]:
for time_slot in time_slots:
overlapping_flights = get_overlapping_flights(flights, time_slot)
model.add_constraint(
sum(assignments[(f.id, resource.id)] for f in overlapping_flights) <= 1
)
# Add custom constraints
for constraint in constraints:
constraint.apply_to_model(model, assignments)
# Define objective function based on weighted goals
objective = 0
for goal in optimization_goals:
objective += goal.weight * goal.calculate_objective(flights, assignments)
model.set_objective(objective, minimize=True)
# Solve the optimization problem
solution = model.solve()
# Return optimized assignments
return extract_assignments(solution, assignments)
The actual implementation uses advanced mixed-integer programming and constraint satisfaction techniques to efficiently solve complex resource allocation problems.
What-If Analysis
SANS.AI provides powerful what-if analysis capabilities for resource planning:
- Scenario Modeling: Testing alternative resource allocation strategies
- Disruption Simulation: Evaluating response to operational disruptions
- Capacity Planning: Analyzing the impact of infrastructure or resource changes
- Schedule Modifications: Assessing the impact of flight schedule changes
- Growth Projection: Planning for traffic growth scenarios
These capabilities help airports proactively plan for changes and develop robust resource strategies.
Integration with External Systems
The Resource Optimization module integrates with external systems to ensure coordinated operations:
- Airline Systems: Coordination with airline resource management platforms
- Ground Handler Systems: Integration with ground service provider systems
- A-CDM Platforms: Coordination with Airport Collaborative Decision Making systems
- FIDS/GIDS: Integration with Flight and Gate Information Display Systems
- Asset Management Systems: Coordination with equipment tracking systems
These integrations ensure that optimization decisions are coordinated across all stakeholders in the airport ecosystem.
The Intelligent Notifications module provides a sophisticated alerting system that delivers timely, relevant, and actionable information to airport stakeholders. This system employs AI-driven prioritization and context awareness to ensure that the right information reaches the right people at the right time.
Notification Types
SANS.AI generates various types of notifications based on operational conditions:
- Alerts: Time-sensitive information requiring immediate attention or action
- Warnings: Potential issues that may require monitoring or future action
- Updates: Important changes to operational status or resources
- Recommendations: AI-generated suggestions for operational improvements
- Informational: Context-providing information without immediate action requirements
Each notification type follows a specific format and prioritization protocol to ensure appropriate handling.
Context-Aware Delivery
The notification system intelligently determines notification delivery based on multiple factors:
- User Role: Matching notifications to relevant job responsibilities
- Current Activity: Awareness of user's active tasks and focus areas
- Location: Physical location within the airport (for mobile users)
- Device Type: Adapting notification format to the receiving device
- Priority Settings: User-configurable notification preferences
This context-awareness ensures that notifications are delivered in the most effective and least disruptive manner for each recipient.
Notification Delivery Channels
SANS.AI can deliver notifications through multiple channels:
| Channel | Primary Use Cases | Features |
|---|---|---|
| Dashboard Alerts | Active system users, control center operations | Visual priority indicators, interactive responses, persistent status |
| Mobile App | Mobile staff, field operations | Push notifications, location-aware alerts, offline capability |
| Non-urgent notifications, detailed information | Comprehensive details, attachment support, threaded conversations | |
| SMS | High-priority alerts requiring immediate attention | Concise messages, device independence, reliable delivery |
| API Webhooks | Integration with external systems | Structured data, customizable payload, system-to-system communication |
The system can be configured to use multiple delivery channels for critical notifications to ensure receipt.
Intelligent Prioritization
SANS.AI employs a sophisticated prioritization system to manage notification importance:
// Example of notification prioritization logic
function calculateNotificationPriority(notification) {
// Base score from notification type
let baseScore = {
'alert': 80,
'warning': 60,
'update': 40,
'recommendation': 30,
'informational': 20
}[notification.type];
// Adjust for operational impact
let operationalMultiplier = 1.0;
switch(notification.operationalImpact) {
case 'critical':
operationalMultiplier = 1.5;
break;
case 'significant':
operationalMultiplier = 1.2;
break;
case 'moderate':
operationalMultiplier = 1.0;
break;
case 'minor':
operationalMultiplier = 0.8;
break;
case 'none':
operationalMultiplier = 0.6;
break;
}
// Time sensitivity factor
let timeFactor = 1.0;
const timeToAction = notification.timeToActionRequired; // in minutes
if (timeToAction < 15) {
timeFactor = 1.5;
} else if (timeToAction < 60) {
timeFactor = 1.2;
} else if (timeToAction > 240) {
timeFactor = 0.8;
}
// Calculate final priority
let priorityScore = baseScore * operationalMultiplier * timeFactor;
// Map to priority levels
if (priorityScore >= 90) return 'critical';
if (priorityScore >= 70) return 'high';
if (priorityScore >= 50) return 'medium';
if (priorityScore >= 30) return 'low';
return 'informational';
}
This prioritization ensures that the most important notifications receive appropriate attention while preventing alert fatigue.
User Configuration
Users can configure notification preferences through the Notification Settings panel:
- Priority Thresholds: Minimum priority level for different delivery channels
- Working Hours: Specification of periods for receiving different notification types
- Focus Areas: Selection of operational areas for which notifications are relevant
- Delivery Preferences: Preferred channels for different notification types
- Notification Grouping: Settings for combining related notifications
These settings ensure that each user receives an appropriate and manageable flow of notifications.
Critical Alert Override
Critical safety and operational alerts will override user preferences to ensure delivery of essential information. These override settings can be configured by system administrators but cannot be disabled entirely.
Notification Content Generation
SANS.AI uses NLG (Natural Language Generation) techniques to create clear, concise notification content:
- Situation Summary: Concise explanation of the current condition
- Operational Impact: Description of how the situation affects operations
- Recommended Actions: Specific steps that should be taken
- Relevant Data: Key metrics and information related to the notification
- Time Sensitivity: Indication of when action is required
The system adjusts content detail based on the delivery channel, with more comprehensive information for dashboard alerts and email, and more concise content for SMS and mobile notifications.
Notification Management
SANS.AI provides tools for managing and tracking notifications:
- Notification Center: Central repository of all current and past notifications
- Acknowledgment Tracking: Monitoring of notification receipt and review
- Escalation Paths: Automatic escalation for unacknowledged critical notifications
- Notification Analytics: Tracking of notification volumes, response times, and effectiveness
- Notification History: Searchable archive of past notifications
These management tools ensure accountability and enable continuous improvement of the notification system.
Every turnaround competes for the same stands, equipment, and people. Allocate too generously and capacity sits idle; too tightly and one late arrival cascades through the afternoon. Turnaround Allocation predicts what each movement will actually need, learns from what your planners decide, and measures both against what happened.
Available as an add-on
Turnaround Allocation is licensed separately from the Standard, Professional, and Enterprise tiers. Talk to support@kquika.com about adding it to your account.
The allocation loop
Most forecasting tools stop at the prediction. This one closes the loop, because the gap between what was predicted and what a planner actually did is the most valuable signal you have.
| Stage | What happens |
|---|---|
| Predict | Each movement is scored for the resources it will need, ranked by urgency |
| Decide | The planner accepts the prediction or allocates by hand, and that choice is recorded |
| Verify | Predictions are compared against the allocations that actually happened |
Those recorded decisions become training data. Models trained this way learn how your operation behaves rather than an industry average, and they keep pace as your stand mix, fleet, and staffing change.
Batch prediction runs off the request path, so scoring a full day of movements does not block anyone.
Constraints the models respect
Constraints reach the models two ways. Some are learned from what your operation has actually done, so a stand that never takes a particular aircraft stops being offered without anyone writing that down. The rest you state directly, in two layers: a set describing what your operation permits in general, and local rules that override it for a single airport without touching the general set, so a restriction at one station does not become a policy change everywhere.
You never have to work out precedence yourself. The platform reports what the combination actually permits between any resource and any aircraft, which is the question a planner is really asking.
Rule sets are versioned. Compare two versions, see exactly what changed, and activate one, which archives the set it replaces rather than editing in place. A bad activation is a rollback, not a repair job.
Knowing what is coming
Allocation is only as good as the schedule behind it. Each airport chooses where its forward schedule comes from, and the preview reports which source answered. A silent fall back to stale data becomes visible instead of quietly degrading tomorrow's plan.
Models trained on your data
Models learn from your own operating record, whether it arrives as a scheduled feed from your systems or as a file you send us. Before a run starts, the readiness check reports which models can train on which of it, so a gap is found before the run rather than after.
Runs start on their own once enough new data has arrived, and can be started on demand at any time. Either way they are queued, monitored, retried, and stopped from the dashboard or the API, so nothing depends on somebody remembering to press anything.
Measuring the result
You set the targets your own operation is judged against, per airport. Where SANS.AI carries a starting default, your own target replaces it, and every target that could apply is reported along with which one is in force and where it came from. Measurements run against live allocations, so the number you report to the board is the same number the models are judged on.
Available through the API
Turnaround Control measures the turns this module plans. See Turnaround Control. Every capability on this page is reachable at /api/v1/frms/ and through the Python and Node clients, so predictions and decisions can flow between SANS.AI and your existing planning systems without anyone retyping them. See API Reference.
Allocation answers what a turnaround will need before the aircraft lands. Control answers what this turnaround is doing right now. The board shows every turn in progress against the schedule it was given, so an overrun is visible while there is still time to move something rather than in tomorrow's report.
Part of the Turnaround add-on
Turnaround Control is licensed alongside Turnaround Allocation. An account that already holds the add-on gets it without any provisioning. Talk to support@kquika.com about adding it.
How a turn is tracked
Nothing on the board is inferred from elapsed time. Every figure traces to a recorded event, which is why an empty board means nothing has been reported rather than that nothing is happening.
| Stage | What happens |
|---|---|
| Record | Milestones arrive from your operations systems, a file you send us, a person on the ramp, or the API, and are appended to a log that is never edited |
| Reduce | The log is folded into task state, completion, and a projected off-block time, on every event and on a fixed tick |
| Raise | Rules run against the reduced state and open an alert against the turn, assigned to whoever owns that task |
Ingest is idempotent on the combination of turnaround, milestone, source, and instant. Replaying a batch after a network failure creates nothing twice, so a feed that retries is safe to point at the endpoint.
Each event carries the source that produced it, and a confidence where the source is a model or a sensor rather than a recorded fact. A milestone from an operator and a milestone from an inference are never presented as the same kind of thing.
The schedule a turn is measured against
Each turnaround is instantiated from a planned turnaround schedule chosen by aircraft type. Tasks are anchored to in-block or off-block rather than to a wall clock, so a schedule that slips two hours needs no replanning: the plan moves with the aircraft.
Anchored offsets are what the board labels A+6 and D-25, meaning six minutes after in-block and twenty five minutes before off-block. Tasks nest, so baggage unload can hold the cargo door and the loader beneath it, and tasks on the critical path are marked because those are the ones that move the departure.
Two clocks, and they are not the same
The board publishes two forward times and they answer different questions. Reporting one where the other belongs is the most common way a turnaround feed misleads an A-CDM platform.
| Time | What it means |
|---|---|
| Computed TOBT | When handling will be finished, doors closed and bridge removed. Pushback and de-icing sit outside it, as the standard defines. This is the value to publish |
| Predicted off-block | When the aircraft will actually leave the stand, pushback included. This is the value that tells you whether the next arrival has a stand |
| Scheduled off-block | What the plan said. Both figures above are reported against it, so the delay is a measurement rather than a claim |
The computed TOBT is compared to the one you published. Drift beyond five minutes means the published value should be reissued, and drift beyond fifteen minutes from the filed estimate is a change the network has to be told about. Both raise an alert rather than waiting for someone to notice.
Where a prediction from the turnaround model exists, it sets the floor for the projected off-block. Once the aircraft goes off-block the measured turnaround is written back onto the prediction that forecast it, so the model has an actual to be judged against instead of only a schedule.
Every prediction is published with a plain reading of how far it can be relied on, in the same words the allocation cards use. A turn that carries one reads like this:
"prediction_quality": {
"model_name": "ForecastIQ Turnaround Time",
"note": "typically within 6 min of what happened on flights it had not seen"
}
Where the model has no error figure of its own, the note falls back to how often it matched past flights it had not seen, and where it has neither it says so rather than offering a number that means nothing.
One thing worth knowing about the allocation cards. The percentage beside a predicted stand is how far the stand, gate, belt and counter models agreed with each other on that flight, which the card labels Agreement. It is not a score for the turnaround duration, and a low value there does not make the duration unreliable. The models can disagree about which stand an aircraft will take while the model measuring how long it sits there is sound.
Scores behind the reading
The scores the reading is drawn from are added to prediction_quality for platform administrators only. An operator credential receives the reading, which is what answers the question a controller is actually asking.
What the rest of the platform contributes
An airport running Safety Features, LiDAR Integration and Resource Optimization already holds information the allocation module never sees, because allocation is trained on an operations export and an export does not record the weather or the ramp.
| Module | What it adds to a turnaround |
|---|---|
| Weather | The conditions on the stand at in-block, so an overrun in fog is distinguishable from an overrun on a clear afternoon |
| Resource Optimization | What is due on the stand next, which is what turns a projected overrun into a stand conflict somebody can act on |
| LiDAR Integration | Crowding in the zone a flight boards from, which is the difference between boarding running late and boarding running late because nobody can reach the gate |
| Safety Features | The alert stream, the evidence trail and the response window that ramp alerts are raised into |
The LiDAR link needs no setup. Gates already carry a position on the terminal map and zones already carry the box they cover, on the same map for the same terminal, which is how the terminal planner draws them together. A gate falling inside a box is the mapping. An airport that connects LiDAR gets the link on the next sweep, and an airport that has not connected it sees nothing rather than a guess.
It runs the other way as well. A turnaround alert appears in Safety Features with the same evidence trail as any other alert, the measured turnaround is written back onto the prediction that forecast it so allocation models can be scored on what happened, and a turn projected past the next aircraft's arrival raises a stand conflict rather than surfacing as a surprise on the day.
What the board gives back to the models
Allocation models learn from what happened, which is why a forward schedule is an input to prediction and never to training. A schedule tells you a flight exists. It does not tell you which stand it took or how long it sat there.
Completed turnarounds do. Every turn that reaches off block records the stand it used, the time it took against the time it was given, and the conditions it ran in, in the same column names as the operations export the models already read. Those rows are available for the next training run, so the record stops ending on the day of your last upload.
Two things an export cannot carry come with them: the weather on the stand at in block, and the boarding zone the flight used. Neither exists in an operations file, and both are things the platform already knows.
A-CDM time stamps
Milestones are recorded against the sixteen numbered A-CDM milestones, and the board reports the highest one a flight has reached. In-block, ground handling start and end, boarding, aircraft ready, start-up requested and approved, off-block, and airborne are all stored under their standard names, so a value can be handed to an A-CDM platform without translation.
Target take-off time is derived from the target off-block and the taxi-out time when nobody has issued one. An issued value is recorded as issued and is never overwritten by a derived one.
Alerts that close themselves
Rules run over the event log rather than over a snapshot, so a rule can ask whether something has failed to happen, which is the interesting question on a ramp. A loader that has not connected three minutes after the aircraft parked is an alert; a loader that connected late is not.
An alert is raised once for a turn, carries a response window, escalates in severity if that window closes with nobody on it, and resolves itself the moment its condition clears. An empty alert rail means the ramp is clean rather than that nobody has looked.
Rules live in the same store as the rest of your notification rules, so a threshold can be changed for one account without a release. Turnaround alerts also appear in Safety Features alongside every other alert, carrying the same evidence trail, with a link back to the turn they came from.
Where the board gets its milestones
Point your operations feed at
/api/v1/turnarounds/movements and the board
builds and advances turnarounds from it on its own. Field
names are matched loosely, so a record is read whatever
else it carries alongside its in-block and off-block times.
Sending an export as a file works the same way and is there
for stations whose systems cannot post to us yet.
A feed is safe to retry. Matching is on the record's own reference, so resending the same movement updates the turnaround rather than creating a second one.
When the record you hold has run out
An operating record ends where it ends, and a board seeded from it shows yesterday. To put the day ahead on the board, ask for a forward schedule instead. Three sources are tried in order and whichever answers is recorded on every turnaround it builds:
| Source | What it is |
|---|---|
| Your operational database | The schedule your own systems hold. Confirmed, and the one to use where you have it |
| A live schedule feed | Published departures and arrivals for your airport from an outside service. Needs a key on the account |
| A public airport board | The same information from an open source. No key needed, and unofficial, so confirm anything you act on |
| Your own recurrence | Flights derived from what has actually operated at your airport, week after week. A starting point, and it says so |
A turnaround built from recurrence may simply not operate. It carries that on its face rather than sitting next to a confirmed one looking identical, and the board marks it.
A record with no in-block or off-block instant is skipped
and counted separately in the response. That is what tells
you a feed has nothing new to report as against a feed that
cannot answer the question, which is what a position feed
is. An AODB or FIDS data connector
whose records carry those instants also feeds the board on
every sync, with no call needed.
What this does not do
Turnaround Control measures the events it is given. It does not watch the stand. There is no computer vision on apron cameras and no speech recognition on ramp radio, so a milestone nobody reports is a milestone the board does not have. The radio panel stays empty until a transcription source posts to it. Where a figure is absent the board says so rather than estimating one.
Available through the API
The board, the task plan, the event log, and the alerts are reachable at /api/v1/turnarounds/ under the read:turnaround and write:turnaround scopes, and through the Python and Node clients. See API Reference.
SANS.AI provides a RESTful API that enables integration with external systems and development of custom applications. This section covers authentication, scopes, endpoints, limits, and error handling.
Machine readable specification
The API is described by an OpenAPI 3.1 document. Every endpoint, parameter, and response below is generated from it, so this page and the API cannot drift apart.
Base URL
https://www.sans-ai.tech
Authentication
The API supports two authentication methods. Both are first class. Choose based on how much control you need over credential lifetime and permissions.
| Method | Best for | Credential lifetime | Permission control |
|---|---|---|---|
| API key | Simple integrations, internal scripts, getting started | Until revoked or expired | Per-key endpoint allowlist |
| OAuth 2.0 client credentials | Server to server integration, third party access, production systems | One hour, then re-issue | Scopes granted per token |
API key authentication
Create a key in the dashboard and send it in the X-API-Key header.
curl https://www.sans-ai.tech/api/v1/flights/history?airport=LHR \
-H "X-API-Key: YOUR_API_KEY"
OAuth 2.0 client credentials
Exchange a client ID and secret for a short lived bearer token, then send that token on every request. Tokens expire after one hour and can be revoked immediately.
Request a token with HTTP Basic authentication:
curl -X POST https://www.sans-ai.tech/api/v1/oauth/token \
-u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
-d "grant_type=client_credentials" \
-d "scope=read:flights read:safety"
Response:
{
"access_token": "sat_xQ9vK2mNp4rT8wY6bL3hJ5dF7gS1zA0cE",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read:flights read:safety"
}
Then call the API:
curl https://www.sans-ai.tech/api/v1/flights/history?airport=LHR \
-H "Authorization: Bearer sat_xQ9vK2mNp4rT8wY6bL3hJ5dF7gS1zA0cE"
Omit scope to receive every scope your client is authorized for. Requesting a scope the client does not hold returns invalid_scope. A token cannot be widened after issue, so request narrowly and re-issue when the integration's needs change.
Credentials may also be sent in the request body instead of the Basic header:
curl -X POST https://www.sans-ai.tech/api/v1/oauth/token \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
Revoking a token
Revocation takes effect immediately. The endpoint returns 200 whether or not the token existed, so it cannot be used to probe for valid tokens.
curl -X POST https://www.sans-ai.tech/api/v1/oauth/revoke \
-u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
-d "token=sat_xQ9vK2mNp4rT8wY6bL3hJ5dF7gS1zA0cE"
Checking a token
curl -X POST https://www.sans-ai.tech/api/v1/oauth/introspect \
-u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
-d "token=sat_xQ9vK2mNp4rT8wY6bL3hJ5dF7gS1zA0cE"
Store the client secret at creation
Client secrets are hashed at rest and shown once, when the client is created. If it is lost, delete the client and create a new one.
Scopes
OAuth tokens carry scopes. Each endpoint requires exactly one. API keys are not scoped; they use the per-key endpoint allowlist instead.
| Scope | Grants |
|---|---|
read:account | Account usage statistics |
read:flights | Live positions, historical movements, statistics, and analytics |
read:frms | Turnaround predictions, trained models, and KPI measurements |
read:frms-rules | Resource rules, rule set versions, and what they permit |
read:frms-schedule | Forward flight schedule configuration and preview |
read:frms-training | Training jobs and readiness checks |
read:lidar | Passenger flow, density, and bottlenecks |
read:maintenance | Maintenance reports and system health |
read:models | Model inventory and training jobs |
read:predictions | Delay and maintenance predictions |
read:resources | Resource utilization and efficiency |
read:safety | Safety incidents, alerts, metrics, and analytics |
read:turnaround | Live turnaround state, milestones, tasks, and alerts |
read:weather | Historical weather observations |
write:frms | Queue prediction runs, record decisions, and verify outcomes |
write:frms-rules | Set local rules, import rule sets, and activate versions |
write:frms-schedule | Change the forward schedule source for an airport |
write:frms-training | Queue, retry, and stop training jobs |
write:maintenance | Schedule maintenance windows |
write:models | Train models and run inference |
write:turnaround | Record milestone events, publish predictions, and work alerts |
List scopes programmatically at GET /api/v1/oauth/scopes.
Authentication endpoints
| Endpoint | Description |
|---|---|
POST /api/v1/oauth/token | Exchange client credentials for an access token |
POST /api/v1/oauth/revoke | Revoke an access token immediately |
POST /api/v1/oauth/introspect | Check whether a token is still active |
GET /api/v1/oauth/scopes | List every scope the API defines |
Endpoints
The public API exposes the operations below. Endpoints not listed here are internal to the SANS.AI web application, are session authenticated, and carry no compatibility guarantee.
Account
| Endpoint | Scope | Description |
|---|---|---|
GET /api/v1/entitlements | read:account | What this credential can reach |
GET /api/v1/health | none | Service health |
GET /api/v1/usage-stats | read:account | Account usage statistics |
Authentication
| Endpoint | Scope | Description |
|---|---|---|
POST /api/v1/oauth/introspect | none | Check whether a token is still active |
POST /api/v1/oauth/revoke | none | Revoke an access token |
GET /api/v1/oauth/scopes | none | List every scope the API defines |
FRMS
| Endpoint | Scope | Description |
|---|---|---|
GET /api/v1/frms/kpi-targets | read:frms | KPI targets that apply here |
POST /api/v1/frms/kpi-targets | write:frms | Set or clear a KPI target |
GET /api/v1/frms/kpis | read:frms | Latest KPI measurement |
GET /api/v1/frms/models | read:frms | List trained FRMS models |
POST /api/v1/frms/predict | write:frms | Predict turnaround resource needs |
POST /api/v1/frms/predict/batch | write:frms | Queue a batch prediction run |
POST /api/v1/frms/predictions/decide | write:frms | Record a planner decision |
POST /api/v1/frms/predictions/verify | write:frms | Verify predictions against actuals |
GET /api/v1/frms/rules/active/{airport} | read:frms-rules | Live rule set for an airport |
GET /api/v1/frms/rules/effect | read:frms-rules | What the current rules permit |
GET /api/v1/frms/rules/local | read:frms-rules | Rules set locally |
POST /api/v1/frms/rules/local | write:frms-rules | Set a local rule |
GET /api/v1/frms/rules/sets | read:frms-rules | Rule set versions |
GET /api/v1/frms/schedule/config/{airport} | read:frms-schedule | Forward schedule configuration |
POST /api/v1/frms/schedule/config/{airport} | write:frms-schedule | Set the forward schedule source |
GET /api/v1/frms/schedule/preview/{airport} | read:frms-schedule | Preview the forward schedule |
GET /api/v1/frms/train/jobs | read:frms-training | Recent FRMS training jobs |
POST /api/v1/frms/train/queue | write:frms-training | Queue an FRMS training run |
POST /api/v1/frms/training/readiness | read:frms-training | Check which models can train |
Flights
| Endpoint | Scope | Description |
|---|---|---|
GET /api/v1/airports/{airportCode}/flights | read:flights | Arrivals and departures for one airport |
GET /api/v1/flights/analytics | read:flights | Flight performance analytics |
GET /api/v1/flights/daily-summary | read:flights | Daily flight summaries |
GET /api/v1/flights/history | read:flights | Historical flight movements |
GET /api/v1/flights/live | read:flights | Live flight positions |
GET /api/v1/flights/statistics | read:flights | Aggregate flight statistics |
LiDAR
| Endpoint | Scope | Description |
|---|---|---|
GET /api/v1/lidar/bottlenecks | read:lidar | Detected passenger flow bottlenecks |
GET /api/v1/lidar/heatmap | read:lidar | Passenger density heatmap |
GET /api/v1/lidar/historical | read:lidar | Historical passenger flow |
GET /api/v1/lidar/real-time | read:lidar | Real-time passenger flow |
Maintenance
| Endpoint | Scope | Description |
|---|---|---|
GET /api/v1/maintenance/reports | read:maintenance | Maintenance reports and system health |
POST /api/v1/maintenance/schedule | write:maintenance | Schedule a maintenance window |
Models
| Endpoint | Scope | Description |
|---|---|---|
GET /api/v1/custom-models | read:models | List custom models |
POST /api/v1/custom-models/train | write:models | Start a training run |
GET /api/v1/custom-models/training | read:models | List training jobs |
POST /api/v1/custom-models/{modelId}/run | write:models | Run a custom model |
GET /api/v1/ml/models | read:models | List available models |
POST /api/v1/models/{modelId}/predict | write:models | Run inference against a specific model |
Predictions
| Endpoint | Scope | Description |
|---|---|---|
POST /api/v1/models/predict/delay | read:predictions | Predict flight delay |
POST /api/v1/models/predict/maintenance | read:predictions | Predict maintenance needs |
Resources
| Endpoint | Scope | Description |
|---|---|---|
GET /api/v1/resource-optimization/resource-utilization | read:resources | Current resource utilization and efficiency |
GET /api/v1/resources/history | read:resources | Historical resource utilization |
Safety
| Endpoint | Scope | Description |
|---|---|---|
GET /api/v1/safety/alerts | read:safety | Active safety alerts |
POST /api/v1/safety/alerts/{alertId}/acknowledge | read:safety | Acknowledge a safety alert and record the decision |
GET /api/v1/safety/analytics | read:safety | Safety analytics |
GET /api/v1/safety/history | read:safety | Historical safety records |
GET /api/v1/safety/metrics | read:safety | Safety metrics |
Turnaround
| Endpoint | Scope | Description |
|---|---|---|
GET /api/v1/turnaround-alerts | read:turnaround | Open turnaround alerts |
POST /api/v1/turnaround-alerts/{alertId}/acknowledge | write:turnaround | Acknowledge an alert |
POST /api/v1/turnaround-alerts/{alertId}/assign | write:turnaround | Assign an alert to a person |
POST /api/v1/turnaround-alerts/{alertId}/resolve | write:turnaround | Resolve an alert |
GET /api/v1/turnarounds | read:turnaround | Turnaround board |
POST /api/v1/turnarounds/from-predictions | write:turnaround | Seed scheduled turnarounds from allocation predictions |
POST /api/v1/turnarounds/from-schedule | write:turnaround | Seed turnarounds from the forward flight schedule |
POST /api/v1/turnarounds/movements | write:turnaround | Feed the board from a movement feed |
GET /api/v1/turnarounds/observations | read:turnaround | Completed turnarounds as training rows |
GET /api/v1/turnarounds/templates | read:turnaround | Planned turnaround schedules |
GET /api/v1/turnarounds/{turnaroundId} | read:turnaround | One turnaround with its milestones, tasks and alerts |
GET /api/v1/turnarounds/{turnaroundId}/events | read:turnaround | Event log for a turnaround |
POST /api/v1/turnarounds/{turnaroundId}/events | write:turnaround | Record milestone events |
GET /api/v1/turnarounds/{turnaroundId}/gantt | read:turnaround | Planned against actual task bars |
POST /api/v1/turnarounds/{turnaroundId}/prediction | write:turnaround | Publish a predicted turnaround duration |
Weather
| Endpoint | Scope | Description |
|---|---|---|
GET /api/v1/weather/history | read:weather | Historical weather observations |
Calling the API
Every endpoint below, with a working example in cURL, Python, and Node. Expand one and copy the language you need. Examples use real parameter values, so they run as written once you supply a key.
Set your key first
The cURL examples read $SANSAI_API_KEY. Export it once with export SANSAI_API_KEY="your-key" and every example works unchanged. The Python and Node clients read the same variable when you omit the key.
The turnaround endpoints are an add-on
The endpoints under /api/v1/frms/ and /api/v1/turnarounds/ are licensed separately from the plan tiers, so holding the scopes is not enough on its own. Without the add-on the FRMS endpoints return 403 with code FRMS_ACCESS_REQUIRED, and the turnaround endpoints return 403 with code INSUFFICIENT_SCOPE naming the scope in required_scope. See Turnaround Allocation and Turnaround Control.
Account
curl "https://www.sans-ai.tech/api/v1/entitlements" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.entitlements()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.entitlements();
curl "https://www.sans-ai.tech/api/v1/health"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.health()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.health();
curl "https://www.sans-ai.tech/api/v1/usage-stats?days=30" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.usage_stats(days=30)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.usageStats({ days: 30 });
Authentication
curl -X POST "https://www.sans-ai.tech/api/v1/oauth/introspect"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.token_info(token="value")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.tokenInfo({ token: "value" });
curl -X POST "https://www.sans-ai.tech/api/v1/oauth/revoke"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.revoke_token(token="value")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.revokeToken({ token: "value" });
curl "https://www.sans-ai.tech/api/v1/oauth/scopes"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.scopes()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.scopes();
FRMS
curl "https://www.sans-ai.tech/api/v1/frms/kpi-targets" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.kpi_targets()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.kpiTargets();
curl -X POST "https://www.sans-ai.tech/api/v1/frms/kpi-targets" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.set_kpi_target()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.setKpiTarget();
curl "https://www.sans-ai.tech/api/v1/frms/kpis" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.kpis()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.kpis();
curl "https://www.sans-ai.tech/api/v1/frms/models" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.frms_models()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.frmsModels();
curl -X POST "https://www.sans-ai.tech/api/v1/frms/predict" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.predict_turnaround()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.predictTurnaround();
curl -X POST "https://www.sans-ai.tech/api/v1/frms/predict/batch" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.queue_turnaround_batch()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.queueTurnaroundBatch();
curl -X POST "https://www.sans-ai.tech/api/v1/frms/predictions/decide" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.record_decision()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.recordDecision();
curl -X POST "https://www.sans-ai.tech/api/v1/frms/predictions/verify" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.verify_predictions()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.verifyPredictions();
curl "https://www.sans-ai.tech/api/v1/frms/rules/active/LHR" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.active_rules("LHR")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.activeRules({ airport: "LHR" });
curl "https://www.sans-ai.tech/api/v1/frms/rules/effect" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.rule_effect()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.ruleEffect();
curl "https://www.sans-ai.tech/api/v1/frms/rules/local" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.local_rules()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.localRules();
curl -X POST "https://www.sans-ai.tech/api/v1/frms/rules/local" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.set_local_rule()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.setLocalRule();
curl "https://www.sans-ai.tech/api/v1/frms/rules/sets" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.rule_sets()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.ruleSets();
curl "https://www.sans-ai.tech/api/v1/frms/schedule/config/LHR" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.schedule_config("LHR")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.scheduleConfig({ airport: "LHR" });
curl -X POST "https://www.sans-ai.tech/api/v1/frms/schedule/config/LHR" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.set_schedule_config("LHR")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.setScheduleConfig({ airport: "LHR" });
curl "https://www.sans-ai.tech/api/v1/frms/schedule/preview/LHR" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.preview_schedule("LHR")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.previewSchedule({ airport: "LHR" });
curl "https://www.sans-ai.tech/api/v1/frms/train/jobs" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.frms_training_jobs()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.frmsTrainingJobs();
curl -X POST "https://www.sans-ai.tech/api/v1/frms/train/queue" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.queue_frms_training()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.queueFrmsTraining();
curl -X POST "https://www.sans-ai.tech/api/v1/frms/training/readiness" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.training_readiness()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.trainingReadiness();
Flights
curl "https://www.sans-ai.tech/api/v1/airports/LHR/flights" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.airport_flights("LHR")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.airportFlights({ airportCode: "LHR" });
curl "https://www.sans-ai.tech/api/v1/flights/analytics?period=30d" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.flight_analytics(period="30d")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.flightAnalytics({ period: "30d" });
curl "https://www.sans-ai.tech/api/v1/flights/daily-summary?airports=LHR,JFK&start_date=2026-08-01&end_date=2026-08-29" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.daily_summaries(
airports="LHR,JFK",
start_date="2026-08-01",
end_date="2026-08-29",
)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.dailySummaries({
airports: "LHR,JFK",
startDate: "2026-08-01",
endDate: "2026-08-29",
});
curl "https://www.sans-ai.tech/api/v1/flights/history?airport=LHR&start_date=2026-08-01&end_date=2026-08-29&limit=500" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.flight_history(
airport="LHR",
start_date="2026-08-01",
end_date="2026-08-29",
limit=500,
)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.flightHistory({
airport: "LHR",
startDate: "2026-08-01",
endDate: "2026-08-29",
limit: 500,
});
curl "https://www.sans-ai.tech/api/v1/flights/live?airport=LHR&company=1&limit=500" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.live_flights(airport="LHR", company=1, limit=500)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.liveFlights({ airport: "LHR", company: 1, limit: 500 });
curl "https://www.sans-ai.tech/api/v1/flights/statistics" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.flight_statistics()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.flightStatistics();
LiDAR
curl "https://www.sans-ai.tech/api/v1/lidar/bottlenecks?terminal=T5" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.lidar_bottlenecks(terminal="T5")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.lidarBottlenecks({ terminal: "T5" });
curl "https://www.sans-ai.tech/api/v1/lidar/heatmap?terminal=T5&zone=A" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.lidar_heatmap(terminal="T5", zone="A")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.lidarHeatmap({ terminal: "T5", zone: "A" });
curl "https://www.sans-ai.tech/api/v1/lidar/historical?terminal=T5&zone=A&timeframe=24h" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.lidar_historical(terminal="T5", zone="A", timeframe="24h")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.lidarHistorical({ terminal: "T5", zone: "A", timeframe: "24h" });
curl "https://www.sans-ai.tech/api/v1/lidar/real-time?terminal=T5&zone=A" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.lidar_real_time(terminal="T5", zone="A")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.lidarRealTime({ terminal: "T5", zone: "A" });
Maintenance
curl "https://www.sans-ai.tech/api/v1/maintenance/reports?company_id=1&status=open" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.maintenance_reports(company_id=1, status="open")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.maintenanceReports({ companyId: 1, status: "open" });
curl -X POST "https://www.sans-ai.tech/api/v1/maintenance/schedule" \
-H "X-API-Key: $SANSAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"system": "Baggage Handling",
"title": "Belt replacement",
"description": "Replace worn drive belt on carousel 3",
"scheduled_date": "2026-09-10T02:00:00Z",
"duration": 4,
"priority": "high"
}'
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.schedule_maintenance(
system="Baggage Handling",
title="Belt replacement",
description="Replace worn drive belt on carousel 3",
scheduled_date="2026-09-10T02:00:00Z",
duration=4,
priority="high",
)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.scheduleMaintenance({
system: "Baggage Handling",
title: "Belt replacement",
description: "Replace worn drive belt on carousel 3",
scheduledDate: "2026-09-10T02:00:00Z",
duration: 4,
priority: "high",
});
Models
curl "https://www.sans-ai.tech/api/v1/custom-models?category=delay_prediction&status=open&include_frms=false" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.custom_models(
category="delay_prediction",
status="open",
include_frms="false",
)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.customModels({
category: "delay_prediction",
status: "open",
includeFrms: "false",
});
curl -X POST "https://www.sans-ai.tech/api/v1/custom-models/train" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.train_model()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.trainModel();
curl "https://www.sans-ai.tech/api/v1/custom-models/training" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.training_jobs()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.trainingJobs();
curl -X POST "https://www.sans-ai.tech/api/v1/custom-models/7/run" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.run_custom_model(7)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.runCustomModel({ modelId: 7 });
curl "https://www.sans-ai.tech/api/v1/ml/models?category=delay_prediction&status=open&limit=500" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.models(category="delay_prediction", status="open", limit=500)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.models({ category: "delay_prediction", status: "open", limit: 500 });
curl -X POST "https://www.sans-ai.tech/api/v1/models/7/predict" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.run_model(7)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.runModel({ modelId: 7 });
Predictions
curl -X POST "https://www.sans-ai.tech/api/v1/models/predict/delay" \
-H "X-API-Key: $SANSAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"scheduled_departure": "2026-09-01T14:30:00Z",
"passenger_count": 180,
"weather_origin": {
"visibility": 3,
"wind_speed": 22
},
"weather_dest": {
"visibility": 10,
"wind_speed": 8
}
}'
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.predict_delay(
scheduled_departure="2026-09-01T14:30:00Z",
passenger_count=180,
weather_origin={"visibility": 3, "wind_speed": 22},
weather_dest={"visibility": 10, "wind_speed": 8},
)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.predictDelay({
scheduledDeparture: "2026-09-01T14:30:00Z",
passengerCount: 180,
weatherOrigin: {"visibility": 3, "wind_speed": 22},
weatherDest: {"visibility": 10, "wind_speed": 8},
});
curl -X POST "https://www.sans-ai.tech/api/v1/models/predict/maintenance" \
-H "X-API-Key: $SANSAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"systems": [
"Baggage Handling",
"Jet Bridge"
],
"prediction_horizon": 30
}'
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.predict_maintenance(
systems=["Baggage Handling", "Jet Bridge"],
prediction_horizon=30,
)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.predictMaintenance({
systems: ["Baggage Handling", "Jet Bridge"],
predictionHorizon: 30,
});
Resources
curl "https://www.sans-ai.tech/api/v1/resource-optimization/resource-utilization" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.resource_utilization()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.resourceUtilization();
curl "https://www.sans-ai.tech/api/v1/resources/history?airport=LHR&resource_type=gates&start_date=2026-08-01&end_date=2026-08-29&limit=500" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.resource_history(
airport="LHR",
resource_type="gates",
start_date="2026-08-01",
end_date="2026-08-29",
limit=500,
)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.resourceHistory({
airport: "LHR",
resourceType: "gates",
startDate: "2026-08-01",
endDate: "2026-08-29",
limit: 500,
});
Safety
curl "https://www.sans-ai.tech/api/v1/safety/alerts?severity=critical&status=open" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.safety_alerts(severity="critical", status="open")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.safetyAlerts({ severity: "critical", status: "open" });
curl -X POST "https://www.sans-ai.tech/api/v1/safety/alerts/9/acknowledge" \
-H "X-API-Key: $SANSAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"note": "Loader was on the adjacent stand"
}'
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.acknowledge_alert(9, note="Loader was on the adjacent stand")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.acknowledgeAlert({ alertId: 9, note: "Loader was on the adjacent stand" });
curl "https://www.sans-ai.tech/api/v1/safety/analytics?period=30d" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.safety_analytics(period="30d")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.safetyAnalytics({ period: "30d" });
curl "https://www.sans-ai.tech/api/v1/safety/history?airport=LHR&start_date=2026-08-01&end_date=2026-08-29&incident_type=runway_incursion&severity=critical&limit=500" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.safety_history(
airport="LHR",
start_date="2026-08-01",
end_date="2026-08-29",
incident_type="runway_incursion",
severity="critical",
limit=500,
)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.safetyHistory({
airport: "LHR",
startDate: "2026-08-01",
endDate: "2026-08-29",
incidentType: "runway_incursion",
severity: "critical",
limit: 500,
});
curl "https://www.sans-ai.tech/api/v1/safety/metrics?period=30d" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.safety_metrics(period="30d")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.safetyMetrics({ period: "30d" });
Turnaround
curl "https://www.sans-ai.tech/api/v1/turnaround-alerts?status=open" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.turnaround_alerts(status="open")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.turnaroundAlerts({ status: "open" });
curl -X POST "https://www.sans-ai.tech/api/v1/turnaround-alerts/9/acknowledge" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.acknowledge_turnaround_alert(9)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.acknowledgeTurnaroundAlert({ alertId: 9 });
curl -X POST "https://www.sans-ai.tech/api/v1/turnaround-alerts/9/assign" \
-H "X-API-Key: $SANSAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"user_id": 4
}'
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.assign_turnaround_alert(9, user_id=4)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.assignTurnaroundAlert({ alertId: 9, userId: 4 });
curl -X POST "https://www.sans-ai.tech/api/v1/turnaround-alerts/9/resolve" \
-H "X-API-Key: $SANSAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"note": "Loader was on the adjacent stand"
}'
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.resolve_turnaround_alert(9, note="Loader was on the adjacent stand")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.resolveTurnaroundAlert({ alertId: 9, note: "Loader was on the adjacent stand" });
curl "https://www.sans-ai.tech/api/v1/turnarounds?airport=LHR&hours=8&state=scheduled" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.turnarounds(airport="LHR", hours=8, state="scheduled")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.turnarounds({ airport: "LHR", hours: 8, state: "scheduled" });
curl -X POST "https://www.sans-ai.tech/api/v1/turnarounds/from-predictions" \
-H "X-API-Key: $SANSAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"limit": 500
}'
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.seed_turnarounds_from_predictions(limit=500)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.seedTurnaroundsFromPredictions({ limit: 500 });
curl -X POST "https://www.sans-ai.tech/api/v1/turnarounds/from-schedule" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.seed_turnarounds_from_schedule()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.seedTurnaroundsFromSchedule();
curl -X POST "https://www.sans-ai.tech/api/v1/turnarounds/movements" \
-H "X-API-Key: $SANSAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"movements": [],
"source": "api"
}'
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.record_turnaround_movements(movements=[], source="api")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.recordTurnaroundMovements({ movements: [], source: "api" });
curl "https://www.sans-ai.tech/api/v1/turnarounds/observations?airport=LHR&since=value&limit=500" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.turnaround_observations(airport="LHR", since="value", limit=500)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.turnaroundObservations({ airport: "LHR", since: "value", limit: 500 });
curl "https://www.sans-ai.tech/api/v1/turnarounds/templates" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.turnaround_templates()
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.turnaroundTemplates();
curl "https://www.sans-ai.tech/api/v1/turnarounds/41?refresh=0" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.turnaround(41, refresh="0")
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.turnaround({ turnaroundId: 41, refresh: "0" });
curl "https://www.sans-ai.tech/api/v1/turnarounds/41/events?limit=500" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.turnaround_events(41, limit=500)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.turnaroundEvents({ turnaroundId: 41, limit: 500 });
curl -X POST "https://www.sans-ai.tech/api/v1/turnarounds/41/events" \
-H "X-API-Key: $SANSAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"code": "FUEL_START",
"occurred_at": "2026-09-01T14:03:00Z",
"source": "api"
}'
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.record_turnaround_events(
41,
code="FUEL_START",
occurred_at="2026-09-01T14:03:00Z",
source="api",
)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.recordTurnaroundEvents({
turnaroundId: 41,
code: "FUEL_START",
occurredAt: "2026-09-01T14:03:00Z",
source: "api",
});
curl "https://www.sans-ai.tech/api/v1/turnarounds/41/gantt" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.turnaround_gantt(41)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.turnaroundGantt({ turnaroundId: 41 });
curl -X POST "https://www.sans-ai.tech/api/v1/turnarounds/41/prediction" \
-H "X-API-Key: $SANSAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"predicted_turnaround_minutes": 52,
"confidence": 0.81
}'
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.publish_turnaround_prediction(41, predicted_turnaround_minutes=52, confidence=0.81)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.publishTurnaroundPrediction({
turnaroundId: 41,
predictedTurnaroundMinutes: 52,
confidence: 0.81,
});
Weather
curl "https://www.sans-ai.tech/api/v1/weather/history?airport=LHR&start_date=2026-08-01&end_date=2026-08-29&limit=500" \
-H "X-API-Key: $SANSAI_API_KEY"
from sansai import SansAI
sansai = SansAI(api_key="YOUR_API_KEY")
result = sansai.weather_history(
airport="LHR",
start_date="2026-08-01",
end_date="2026-08-29",
limit=500,
)
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const result = await sansai.weatherHistory({
airport: "LHR",
startDate: "2026-08-01",
endDate: "2026-08-29",
limit: 500,
});
Response format
All requests and responses use JSON. Every response carries a meta object with a request identifier, the response time, and your current position against every limit that applies.
{
"flights": [
{
"flight_number": "UA123",
"airline": "United Airlines",
"origin": "JFK",
"destination": "LAX",
"scheduled_departure": "2026-08-15T14:30:00Z",
"actual_departure": "2026-08-15T14:45:00Z",
"status": "en_route",
"delay_minutes": 15,
"gate": "A12",
"latitude": 39.8282,
"longitude": -98.5795,
"altitude": 35000
}
],
"count": 1,
"filters": {
"airport": "JFK",
"start_date": "2026-08-01",
"end_date": "2026-08-15"
},
"meta": {
"request_id": "bbb0eb3ab9294a2cb883092f01cc5741",
"generated_at": "2026-08-29T14:58:28.921Z",
"api_version": "1.2.0",
"rate_limit": {
"limit_per_minute": 60,
"limit_per_day": 10000,
"used_today": 41,
"remaining_today": 9959
},
"subscription": {
"plan": "Professional",
"max_api_calls_per_month": 50000,
"used_this_month": 41203,
"remaining_this_month": 8797
}
}
}
Use meta.generated_at for timestamps
It is RFC 3339 UTC and ends in Z. Any timestamp field inside a payload is deprecated, carries no timezone offset, and will be read as local time by most date parsers.
Result sizes
List endpoints accept a limit parameter. They do not paginate. Values above each ceiling are clamped. Split larger windows using start_date and end_date.
| Endpoint | Default | Maximum |
|---|---|---|
| Flight history | 500 | 2,000 |
| Resource history | 500 | 2,000 |
| Weather history | 500 | 1,000 |
| Safety history | 500 | 1,000 |
| Model list | 100 | 500 |
| Live flights | 50 | 100 |
Rate limits and quotas
Three separate ceilings apply, and they fail with different codes. Your current position against all three is in every response.
| Limit | Scope | Resets | Error code |
|---|---|---|---|
| Per-minute and per-day rate limit | One key or client | Within the window | RATE_LIMIT_EXCEEDED |
| Monthly call allowance | Your account, across every key it owns | Start of the calendar month | PLAN_QUOTA_EXCEEDED |
| Minimum plan tier | Optional, set per credential | On upgrade | SUBSCRIPTION_REQUIRED |
Monthly call allowance by plan:
| Plan | API calls per month |
|---|---|
| Standard | 10,000 |
| Professional | 50,000 |
| Enterprise | 75,000 |
| Custom | Negotiated |
Limit information is returned in response headers:
X-Request-Id: bbb0eb3ab9294a2cb883092f01cc5741
X-API-Version: 1.2.0
X-RateLimit-Limit-Minute: 60
X-RateLimit-Limit-Day: 10000
X-RateLimit-Remaining-Day: 9959
X-RateLimit-Used-Day: 41
X-Subscription-Plan: Professional
X-Plan-Quota-Month: 50000
X-Plan-Quota-Remaining-Month: 8797
The two 429s need different handling
RATE_LIMIT_EXCEEDED clears within the window, so retry after the Retry-After delay. PLAN_QUOTA_EXCEEDED does not clear until the next calendar month, so retrying achieves nothing. Check meta.subscription.remaining_this_month before starting a large batch.
Error handling
The API uses standard HTTP status codes. Every error body carries a stable machine readable code. Branch on that, not on the error text, which is written for humans and may be reworded.
{
"error": "No trained delay prediction model is available for this account.",
"code": "NO_DATA_AVAILABLE",
"resource": "delay_prediction_model",
"meta": {
"request_id": "0012991b8bdc40b094531bcc1c4b2a9a",
"generated_at": "2026-08-29T14:58:28.923Z",
"api_version": "1.2.0"
}
}
| Status | Code | Meaning | Retry? |
|---|---|---|---|
| 400 | invalid_scope | Scope unknown, or not granted to this client | No |
| 400 | unsupported_grant_type | Only client_credentials is supported | No |
| 401 | invalid_client | Client authentication failed | No |
| 401 | INVALID_TOKEN | Bearer token unknown, expired, or revoked | Re-issue a token |
| 401 | Missing, invalid, inactive, or expired API key | No, fix the key | |
| 403 | INSUFFICIENT_SCOPE | Token lacks the scope this endpoint requires | Re-issue with the scope |
| 403 | SUBSCRIPTION_REQUIRED | Plan tier below what the credential requires | No, upgrade |
| 403 | ENDPOINT_NOT_ALLOWED | Key is not permitted to call this endpoint | No |
| 403 | IP_NOT_ALLOWED | Source IP not on the credential allowlist | No |
| 403 | FRMS_ACCESS_REQUIRED | Turnaround Allocation add-on not enabled | No, request access |
| 404 | NO_DATA_AVAILABLE | No stored records or trained model exist | No |
| 429 | RATE_LIMIT_EXCEEDED | Per-minute or per-day limit | Yes, after backoff |
| 429 | PLAN_QUOTA_EXCEEDED | Monthly allowance used | Not until next month |
| 502 | PREDICTION_FAILED | A model was found but inference failed | Yes |
Insufficient scope responses also carry a challenge header naming what is missing:
WWW-Authenticate: Bearer realm="SANS.AI", error="insufficient_scope",
error_description="This token does not carry the write:maintenance scope.",
scope="write:maintenance"
Data guarantees
Every 200 response carries observed records or trained model output. The API never substitutes estimated, sample, or heuristic values. Where no records or no trained model exist, the endpoint returns 404 with NO_DATA_AVAILABLE so that absence is never mistaken for a measurement.
Client libraries
Official clients, generated from the same specification as this page. Authentication, token refresh, retries and rate limits are handled for you.
- Python:
pip install kquika-sansai - TypeScript and JavaScript:
npm install @kquika-inc/sansai
Python, using an API key:
import datetime
import os
from sansai import SansAI
sansai = SansAI(api_key=os.environ["SANSAI_API_KEY"])
for flight in sansai.live_flights(airport="LHR"):
print(flight.flight_number, flight.status, flight.delay_minutes)
history = sansai.flight_history(
airport="LHR",
start_date=datetime.date(2026, 8, 1),
end_date=datetime.date(2026, 8, 29),
)
print(history.meta.subscription.remaining_this_month)
Python, using OAuth. The client exchanges the credentials and refreshes the token before expiry without you doing anything:
import os
from sansai import SansAI
sansai = SansAI(
client_id=os.environ["SANSAI_CLIENT_ID"],
client_secret=os.environ["SANSAI_CLIENT_SECRET"],
scope="read:flights read:lidar",
)
zones = sansai.lidar_bottlenecks(terminal="T5")
TypeScript:
import { SansAI } from "@kquika-inc/sansai";
const sansai = new SansAI({ apiKey: process.env.SANSAI_API_KEY });
const flights = await sansai.liveFlights({ airport: "LHR" });
flights.forEach((f) =>
console.log(f.flight_number, f.status, f.delay_minutes),
);
console.log(flights.meta?.subscription?.remainingThisMonth);
Both clients raise typed errors, so you can catch the case you care about rather than branching on status codes:
from sansai import NoDataError, QuotaExceededError, RateLimitError
try:
prediction = sansai.predict_delay(scheduled_departure="2026-09-01T14:30:00Z")
except NoDataError:
print("no trained delay model on this account yet")
except QuotaExceededError:
print("monthly allowance used, resets next month")
except RateLimitError:
print("rate limited, the client already retried with backoff")
Send real requests to the SANS.AI Platform API straight from this page. Paste your key, choose an endpoint and see exactly what your integration will receive, including status, latency, request ID and your remaining plan allowance. The console writes the matching cURL, Python and Node code as you edit, so a working call moves into your codebase in one copy.
Live data, live quota
Requests run against production with your credential and count toward your plan's daily rate limit and monthly quota. Write endpoints such as maintenance scheduling and FRMS decisions create real records. Your key stays in this browser tab and is sent only to the SANS.AI API.
https://www.sans-ai.tech
Keys are issued to each integrating system by your SANS.AI administrator. Public endpoints such as /api/v1/health run without one.
/api/v1/health
public
// JSON payload with meta.request_id,
// meta.rate_limit and meta.subscription
// Response headers appear here.
Every endpoint card in the API Reference carries a Run in console button that loads it here with sample values.
This section addresses common questions about SANS.AI's functionality, implementation, and best practices.
General Questions
What are the primary benefits of implementing SANS.AI?
SANS.AI provides multiple operational benefits including improved efficiency through intelligent resource allocation, enhanced safety through proactive monitoring, better passenger experience through optimized flows, reduced delays through predictive analytics, and cost savings through optimized resource utilization.
What types of airports can use SANS.AI?
SANS.AI runs as a managed service, so a regional airport and a major hub use the same platform and see the same capabilities. What differs is the modules enabled on your account and the volume behind them, which is a licensing decision rather than an infrastructure one.
How does SANS.AI integrate with existing airport systems?
SANS.AI is designed to work alongside existing airport systems through industry-standard APIs and integration methods. It can connect with AODB systems, FIDS, resource management tools, and other operational systems. Our implementation team provides comprehensive integration support to ensure seamless data flow.
How accurate is the predictive analytics module?
Accuracy depends on how much of your own history the models have learned from, so the honest answer is that it is measured rather than promised. Every prediction carries a confidence value and names the model behind it, and accuracy is scored against recorded outcomes so you can see how the models perform on your routes. Short-horizon predictions are consistently stronger than long-horizon ones, and models improve as more of your operational data flows through.
What security measures are in place to protect sensitive data?
SANS.AI implements industry-leading security protocols including end-to-end encryption, role-based access controls, secure API authentication, and comprehensive audit logging. The system is regularly tested through third-party security assessments and penetration testing to ensure compliance with international data protection standards.
This section provides solutions to common issues that may arise during the operation of SANS.AI.
Data is missing or out of date
Almost every reporting problem traces back to a data connection rather than the platform. Start in Data Connectors on the dashboard, which shows every source, its last successful sync, and the reason for any failure.
| What you see | Usual cause | What to do |
|---|---|---|
| A connector shows a failed sync | Credentials rotated on the source system, or the source is unreachable | Re-enter the credentials on the connector. If the source sits behind a firewall, confirm it still accepts our connection |
| Data stops at a certain date | The source system changed its schema or field names | Tell support which source and which date. Field mapping is corrected on our side |
| Flights appear late or not at all | The upstream feed is delayed | Compare against the source directly. If the source has the movement and we do not, raise it with the sync timestamp |
| Numbers disagree with your own reports | A different time basis | Confirm both sides are using UTC. Any timestamp field inside an API payload is deprecated and carries no offset, so use meta.generated_at |
API calls are failing
Every error response carries a stable code and a meta.request_id. Branch on the code, and quote the request id to support.
| Symptom | Check |
|---|---|
| 401 on every call | The key is inactive, expired, or sent in the wrong header. It belongs in X-API-Key. With the Python client, prefix="" is required or the key goes out as a bearer token |
403 INSUFFICIENT_SCOPE | The OAuth token was issued without the scope this endpoint needs. The WWW-Authenticate header names the missing scope. Re-issue with it |
403 ENDPOINT_NOT_ALLOWED | The key carries an endpoint allowlist that excludes this route. Widen it in the dashboard or use a different key |
404 NO_DATA_AVAILABLE | Not a fault. No stored records or no trained model exist for the request, and the API returns this rather than inventing a number |
429 RATE_LIMIT_EXCEEDED | Short window limit. Back off for the Retry-After delay. The official clients already do this for you |
429 PLAN_QUOTA_EXCEEDED | Monthly allowance used. Retrying will not help until the next calendar month. Check meta.subscription.remaining_this_month before a large batch |
| Requests hang or time out | Confirm outbound HTTPS to www.sans-ai.tech is permitted from the calling host. No inbound access to your network is needed |
Predictions look wrong or are missing
Prediction endpoints return a 404 rather than a guess when no trained model exists for your account. On a new account that is expected until enough of your history has been processed.
- Check Custom AI Models for model status and the date of the last training run
- Every prediction carries a
confidencevalue and names the model that produced it. Low confidence on a route with little history is the model reporting its own uncertainty rather than a fault - If predictions were accurate and have drifted, something upstream usually changed. A new stand allocation policy or a schedule change is worth mentioning when you raise it
LiDAR results look inaccurate
The sensing layer is yours, so this is the one area where the fix is usually on your side.
- Check that sensors sit where they were installed and nothing obstructs them. Seasonal retail fixtures and temporary signage are common causes
- Confirm the terminal layout held in the platform still matches the physical layout. A moved checkpoint changes zone boundaries
- Verify sensor firmware with your equipment supplier
- Run the calibration routine from the LiDAR section of the dashboard after any physical change
Contacting support
Email contact@kquika.com. Response times follow your plan, and Enterprise accounts have a named contact with out-of-hours cover.
Four things make a ticket resolvable on the first reply:
| Include | Why it helps |
|---|---|
The request_id from meta on a failing response | It identifies the exact call, including what was returned and why |
| The time, with a timezone | Narrows the search when there is no request id, such as a dashboard issue |
| Airport, and the flight or resource involved | Scopes the question to the records concerned |
| What you expected instead | Separates a fault from a difference of definition, which is the more common cause |