This document explains the callback API endpoints that sim.ai can use to monitor watched flights and send alerts.
To test the integration, use the provided test script:
# 1. Create a flight in the app (Watch Flight button)
# 2. Copy the flight ID from browser console
# 3. Run test script:
./test-sim-integration.sh abc-123-def-456The script will:
- ✅ Verify flight exists
- ✅ Fetch baseline weather
- ✅ Check current weather
- ✅ Compare and detect changes
- ✅ Optionally create test alert
┌──────────────────────────────────────────────────────────────┐
│ User Saves Flight │
│ │ │
│ ▼ │
│ POST /api/watch-route │
│ ├─→ Saves to Supabase (generates flight_id: UUID) │
│ └─→ Sends webhook to sim.ai │
│ │
│ Webhook Payload: │
│ { │
│ "flight_id": "abc-123-def-456", ← STORE THIS! │
│ "pilot_email": "pilot@example.com", │
│ "departure": "KSQL", │
│ "arrival": "KSMF", │
│ "baseline_weather": {...} │
│ } │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ Sim.ai Periodic Check │
│ (every 30 minutes) │
│ │
│ 1. Use stored flight_id from webhook: │
│ GET /api/flights/abc-123-def-456/check-weather?compare=true
│ ────────────────┬──────────── │
│ │ │
│ REQUIRED: Flight ID │
│ │
│ 2. API returns: │
│ • Baseline weather (when saved) │
│ • Current weather (live METAR) │
│ • changes[] array with severity │
│ │
│ 3. If high-severity changes: │
│ PATCH /api/flights/abc-123-def-456 │
│ ────────────────┬──────────── │
│ │ │
│ REQUIRED: Flight ID │
│ │
│ Body: { │
│ "has_alert": true, │
│ "alert_message": "Thunderstorms developing..." │
│ } │
│ │
│ 4. Send email to pilot │
│ │
│ 5. User returns to app → sees alert │
└──────────────────────────────────────────────────────────────┘
When a flight is created:
// Webhook sent to sim.ai
{
"flight_id": "abc-123-def-456", // ← SAVE THIS ID
"departure": "KSQL",
"arrival": "KSMF",
...
}To check weather for that flight:
# Use the flight_id in the URL path
GET /api/flights/abc-123-def-456/check-weather?compare=true
└──────┬──────┘
Flight ID (required)To update with an alert:
# Use the same flight_id
PATCH /api/flights/abc-123-def-456
└──────┬──────┘
Flight ID (required)Endpoint: GET /api/flights/{flight_id}/check-weather
Description: Fetches current weather and compares it with baseline weather saved when flight was created.
Required Parameters:
{flight_id}(in URL path): The UUID of the flight to check- This is returned when you create a flight via webhook
- Format: UUID (e.g.,
abc123-def456-ghi789)
Optional Query Parameters:
compare=true: Returns a detailed comparison with detected changes and severity levels
Example Requests:
# Basic check (returns baseline + current weather)
curl https://your-app.vercel.app/api/flights/abc-123-def/check-weather
# With comparison (recommended - includes automatic diff)
curl https://your-app.vercel.app/api/flights/abc-123-def/check-weather?compare=trueError Responses:
400 Bad Request: Flight ID is missing or invalid404 Not Found: Flight ID doesn't exist in database410 Gone: Flight exists but is no longer active500 Internal Server Error: Server error fetching weather
Example Response (with compare=true):
{
"flight_id": "abc123",
"departure": "KSQL",
"arrival": "KSMF",
"flight_date": "2026-01-26T14:00:00Z",
"baseline_weather": {
"stations": [
{
"station": "KSQL",
"metar": {
"rawOb": "KSQL 251853Z 28008KT 10SM FEW050 15/08 A3012",
"windSpeed": 8,
"windDir": 280,
"visibility": 10,
"ceiling": null,
"flightCategory": "VFR"
}
}
]
},
"current_weather": {
"stations": [
{
"station": "KSQL",
"metar": {
"rawOb": "KSQL 251953Z 27015G25KT 5SM +TSRA BKN020 14/12 A3008",
"windSpeed": 15,
"windGust": 25,
"windDir": 270,
"visibility": 5,
"ceiling": 2000,
"flightCategory": "IFR"
}
}
]
},
"last_checked": "2026-01-25T19:53:00Z",
"changes": [
{
"station": "KSQL",
"field": "visibility",
"baseline_value": "10 SM",
"current_value": "5 SM",
"severity": "high",
"description": "Visibility changed from 10 to 5 statute miles"
},
{
"station": "KSQL",
"field": "wind",
"baseline_value": "8kt",
"current_value": "15kt G25kt",
"severity": "high",
"description": "Wind changed from 8kt to 15kt gusting 25kt"
},
{
"station": "KSQL",
"field": "weather",
"baseline_value": "No thunderstorms",
"current_value": "Thunderstorms present",
"severity": "high",
"description": "Thunderstorm activity has developed"
},
{
"station": "KSQL",
"field": "flight_category",
"baseline_value": "VFR",
"current_value": "IFR",
"severity": "high",
"description": "Flight category changed from VFR to IFR"
}
]
}What Gets Compared:
- ✅ Visibility (alerts if drops ≥2 SM or below 5 SM)
- ✅ Ceiling (alerts if changes ≥1000 ft or below 3000 ft AGL)
- ✅ Wind (alerts if speed changes ≥10kt or gusts >25kt)
- ✅ Weather phenomena (alerts on new TS, precipitation)
- ✅ Flight category (alerts on VFR→MVFR→IFR→LIFR changes)
Severity Levels:
high: Immediate safety concern (IFR, thunderstorms, gusts >25kt)medium: Marginal VFR or moderate changeslow: Minor changes within acceptable limits
Endpoint: PATCH /api/flights/{flight_id}
Description: Updates a flight record with alert information. Use this after detecting significant weather changes.
Example Request:
curl -X PATCH https://your-app.vercel.app/api/flights/abc123 \
-H 'Content-Type: application/json' \
-d '{
"has_alert": true,
"alert_message": "Thunderstorm activity (TSRA) now reported at KSQL with gusts to 25kt. Visibility reduced to 5SM. Flight category degraded to IFR. Consider delaying departure or filing IFR.",
"alert_severity": "high",
"current_weather": { ...current weather object... }
}'Request Body:
{
"has_alert": true,
"alert_message": "Human-readable alert message",
"alert_severity": "low" | "medium" | "high",
"current_weather": { /* latest weather data */ }
}Response:
{
"success": true,
"flight": {
"id": "abc123",
"has_alert": true,
"alert_message": "...",
"alert_severity": "high",
"alert_created_at": "2026-01-25T19:53:00Z",
...
}
}Endpoint: GET /api/flights/{flight_id}
Description: Retrieves full flight details including baseline weather and any existing alerts.
Example Request:
curl https://your-app.vercel.app/api/flights/abc123Response:
{
"flight": {
"id": "abc123",
"pilot_email": "pilot@example.com",
"pilot_name": "John Doe",
"departure": "KSQL",
"arrival": "KSMF",
"flight_date": "2026-01-26T14:00:00Z",
"route_data": { /* route geometry, waypoints */ },
"baseline_weather": { /* weather at save time */ },
"current_weather": { /* latest weather */ },
"has_alert": false,
"alert_message": null,
"alert_severity": null,
"is_active": true,
"created_at": "2026-01-25T18:00:00Z",
"last_weather_check": "2026-01-25T19:53:00Z"
}
}Step 1: Fetch Active Flights from Supabase
// Supabase REST API
GET https://mbbkzftkrsksjlpknfvo.supabase.co/rest/v1/watched_flights
?is_active=eq.true
&flight_date=gte.now()
&select=*
Headers:
apikey: {SUPABASE_ANON_KEY}
Authorization: Bearer {SUPABASE_ANON_KEY}Step 2: For Each Flight, Check Weather Changes
GET https://your-app.vercel.app/api/flights/{flight.id}/check-weather?compare=trueStep 3: Analyze Changes
Use the changes array from the response. If any changes have severity: "high" or severity: "medium":
const hasSignificantChanges = response.changes.some(
change => change.severity === 'high' || change.severity === 'medium'
)Step 4: Create Alert Message
Example with AI agent:
You are an aviation weather analyst. Based on these weather changes, create a concise alert message for a pilot:
Changes detected:
${JSON.stringify(response.changes, null, 2)}
Flight details:
- Route: ${response.departure} → ${response.arrival}
- Scheduled: ${response.flight_date}
Generate a pilot-friendly alert message (2-3 sentences) explaining:
1. What changed
2. Flight safety impact
3. Recommended action (delay, file IFR, etc.)
Step 5: Update Flight with Alert
PATCH https://your-app.vercel.app/api/flights/{flight.id}
Body: {
has_alert: true,
alert_message: "Generated alert message",
alert_severity: "high",
current_weather: response.current_weather
}Step 6: Send Email to Pilot
To: ${flight.pilot_email}
Subject: ⚠️ Weather Alert: ${flight.departure} → ${flight.arrival}
Hi ${flight.pilot_name},
Weather conditions have changed for your upcoming flight:
Route: ${flight.departure} → ${flight.arrival}
Scheduled: ${flight.flight_date}
Alert: ${alert_message}
Severity: ${alert_severity}
View your flight: https://your-app.vercel.app/flights/${flight.id}
Review current conditions and consider regenerating your flight plan.
Safe skies,
FlightAdvisor
# Plan a route in the app and click "Watch Flight"
# This will create a flight and send webhook to sim.aicurl "https://your-app.vercel.app/api/flights/YOUR_FLIGHT_ID/check-weather?compare=true"curl -X PATCH "https://your-app.vercel.app/api/flights/YOUR_FLIGHT_ID" \
-H 'Content-Type: application/json' \
-d '{
"has_alert": true,
"alert_message": "Test alert: Thunderstorms developing along route",
"alert_severity": "high"
}'Refresh the FlightAdvisor app - you should see an alert banner for the flight.
In sim.ai workflow, you'll need:
FLIGHTADVISOR_APP_URL=https://your-app.vercel.app
SUPABASE_URL=https://mbbkzftkrsksjlpknfvo.supabase.co
SUPABASE_ANON_KEY=sb_publishable_nya1KNlaDpWOKkRlCtRiYg_hvh4xkjW- Check weather endpoint: Safe to call every 30 minutes per flight
- METAR updates: Typically updated hourly, more frequently in changing conditions
- Recommended: Check active flights every 30 minutes, or 1 hour for stable conditions
All endpoints return standard HTTP status codes:
200 OK: Success400 Bad Request: Invalid parameters404 Not Found: Flight not found500 Internal Server Error: Server error
Example Error Response:
{
"error": "Flight not found"
}-
Flights remain active until:
flight_datehas passed- User deletes the flight
is_activeis set to false
-
Recommended: Auto-deactivate flights 24 hours after scheduled departure time
- All endpoints use Supabase service role key for authentication
- No user authentication required for callback endpoints
- Flight IDs are UUIDs (hard to guess)
- Consider adding API key authentication if needed for production
For issues or questions about the API, check: