SimTraffic feed integration with VATSWIM
This document describes how SimTraffic can push flight timing data directly to PERTI's VATSWIM API.
PERTI receives flight timing data from SimTraffic to update metering, departure sequence, and arrival times for flights on the VATSIM network. This integration uses a push model where SimTraffic sends updates to our API endpoint.
POST https://perti.vatcscc.org/api/swim/v1/ingest/simtraffic
Use the Authorization header with a Bearer token:
Authorization: Bearer swim_sys_simtraffic_d1b8e35e297f4d30b2b5b4d2
Alternative: Use the X-API-Key header if Bearer tokens are inconvenient:
X-API-Key: swim_sys_simtraffic_d1b8e35e297f4d30b2b5b4d2
Content-Type: application/json
Authorization: Bearer swim_sys_simtraffic_d1b8e35e297f4d30b2b5b4d2
{
"mode": "push",
"flights": [
{
"callsign": "UAL123",
"departure_afld": "KORD",
"arrival_afld": "KJFK",
"departure": {
"push_time": "2026-01-27T14:30:00Z",
"taxi_time": "2026-01-27T14:35:00Z",
"sequence_time": "2026-01-27T14:38:00Z",
"holdshort_time": "2026-01-27T14:40:00Z",
"runway_time": "2026-01-27T14:42:00Z",
"takeoff_time": "2026-01-27T14:45:00Z",
"edct": "2026-01-27T14:40:00Z"
},
"arrival": {
"eta": "2026-01-27T17:15:00Z",
"eta_mf": "2026-01-27T17:00:00Z",
"eta_vertex": "2026-01-27T16:45:00Z",
"on_time": "2026-01-27T17:18:00Z",
"metering_fix": "CAMRN",
"rwy_assigned": "31L"
},
"status": {
"departed": true,
"arrived": false,
"in_artcc": "ZDC",
"delay_value": 5
}
}
]
}
| Field | Type | Required | Description |
callsign | string | Yes | Aircraft callsign (e.g., "UAL123") |
departure_afld | string | Recommended | Departure ICAO (helps match flight) |
arrival_afld | string | Recommended | Arrival ICAO (helps match flight) |
gufi | string | Optional | Direct GUFI lookup if known |
All times in ISO 8601 UTC format (e.g., 2026-01-27T14:30:00Z)
> FIXM Migration Note: As of 2026-01-27, SWIM writes to both legacy (out_utc, off_utc) and
> FIXM-aligned (actual_off_block_time, actual_time_of_departure) columns. After the 30-day
> transition period, legacy columns will be deprecated. API consumers should use FIXM field names.
| Field | Description | Legacy Column | FIXM Column (Preferred) |
departure.push_time | Actual pushback time (T13 AOBT) | out_utc | actual_off_block_time |
departure.taxi_time | When taxi begins | taxi_time_utc | taxi_start_time |
departure.sequence_time | Departure sequence assignment | sequence_time_utc | departure_sequence_time |
departure.holdshort_time | Hold short point entry | holdshort_time_utc | hold_short_time |
departure.runway_time | Runway entry time | runway_time_utc | runway_entry_time |
departure.takeoff_time | Actual takeoff (T11 ATOT) | off_utc | actual_time_of_departure |
departure.edct | Expected Departure Clearance Time | edct_utc | edct_utc |
| Field | Description | Legacy Column | FIXM Column (Preferred) |
arrival.eta | Estimated arrival at runway | eta_utc, eta_runway_utc | estimated_time_of_arrival, estimated_runway_arrival_time |
arrival.eta_mf or arrival.mft | STA at meter fix | metering_time | metering_time |
arrival.eta_vertex or arrival.vt | STA at vertex/corner post | eta_vertex | eta_vertex |
arrival.on_time | Actual landing (T12 ALDT) | on_utc | actual_landing_time |
arrival.metering_fix | Meter fix identifier (e.g., "CAMRN") | metering_point | metering_point |
arrival.rwy_assigned | Assigned arrival runway (e.g., "31L") | arr_runway | arr_runway |
| Field | Type | Description | SWIM Column |
status.departed | boolean | Flight has departed | phase='enroute' |
status.arrived | boolean | Flight has landed | phase='arrived' |
status.in_artcc | string | Current ARTCC (e.g., "ZDC") | current_artcc |
status.delay_value | integer | TBFM delay in minutes | metering_delay |
{
"success": true,
"data": {
"processed": 50,
"updated": 45,
"not_found": 5,
"errors": 0,
"error_details": []
},
"meta": {
"source": "simtraffic",
"mode": "push",
"batch_size": 50
},
"timestamp": "2026-01-27T15:30:00Z"
}
{
"error": true,
"message": "Description of the error",
"status": 400,
"code": "ERROR_CODE"
}
| Code | HTTP | Description |
UNAUTHORIZED | 401 | Invalid or missing API key |
NOT_AUTHORITATIVE | 403 | API key lacks write permission |
MISSING_BODY | 400 | Request body is empty |
INVALID_JSON | 400 | JSON parse error |
MISSING_FLIGHTS | 400 | No "flights" array in body |
BATCH_TOO_LARGE | 400 | More than 500 flights |
SERVICE_UNAVAILABLE | 503 | Database temporarily unavailable |
Flights are matched in PERTI's database by:
1. GUFI (if provided) - Direct lookup by globally unique flight identifier
2. Callsign + Destination - Most recent active flight with matching callsign and arrival airport
3. Callsign only - Most recent active flight with matching callsign
For best matching accuracy, include departure_afld and arrival_afld in each record.
Push updates when:
batch = []
last_push = now()
on_flight_update(flight):
batch.append(format_flight(flight))
# Push immediately for arrivals/departures
if flight.just_departed or flight.just_landed:
push_batch(batch)
batch = []
last_push = now()
every 30 seconds:
if len(batch) > 0 or (now() - last_push) > 120 seconds:
push_batch(batch)
batch = []
last_push = now()
curl -X POST https://perti.vatcscc.org/api/swim/v1/ingest/simtraffic \
-H "Content-Type: application/json" \
-H "Authorization: Bearer swim_sys_simtraffic_d1b8e35e297f4d30b2b5b4d2" \
-d '{
"mode": "push",
"flights": [
{
"callsign": "DAL456",
"arrival_afld": "KATL",
"arrival": {
"eta": "2026-01-27T18:30:00Z",
"eta_mf": "2026-01-27T18:15:00Z",
"metering_fix": "ERLIN",
"rwy_assigned": "26R"
},
"status": {
"departed": true,
"delay_value": 3
}
}
]
}'
Document version: 1.1.0 | Last updated: 2026-01-27