Files
Flights/api_docs/stafftraveler_captures
Trey t 6005146e75 Airline integration work: AirlineLoadService updates, docs, JSX scripts
- AirlineLoadService: pass airport DB for timezone-aware date strings,
  add browser-shaped headers for United, expand JetBlue/Alaska/Emirates
  signatures to take origin, log/parse fixes for Korean Air.
- FlightsApp: build AirlineLoadService with the airport DB and inject it.
- JSX: continued WebView-based fetcher work plus updated JSX_NOTES.
- Docs: add AIRLINE_INTEGRATION_GUIDE.md, drop the old AIRLINE_API_SPEC.md,
  add api_docs/ (StaffTraveler reverse-engineering captures + findings).
- Scripts: jsx_cdp_probe, jsx_live_monitor, jsx_swift_smoke for JSX
  protocol exploration.
- .gitignore: exclude airlines/ (local-only APK/IPA reverse-engineering).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:21:30 -05:00
..

StaffTraveler API captures

Real request/response pairs captured from the iOS app com.stafftraveler.webview v3.12.0 (build 1880000346) against api.stafftraveler.com on 2026-04-22. All captures are by user 3NNPesQMiMRNYnPmuQzh6w2YKyh1 (stafftraveler@treymail.com, WN/Southwest, airline ST code st_SWA).

Auth

All command-API calls are authenticated with:

Authorization: Bearer <Firebase ID token>

Token issued by securetoken.google.com/stafftraveler-prod, aud=stafftraveler-prod, ~1h TTL. The captured tokens are already expired — do not try to reuse them. To get a new one, sign in via Firebase Auth REST against API key AIzaSyC2zG6ArnguzzdWsLYV1qjQznma0zl1Q0s (needs X-Android-Package + X-Android-Cert headers or iOS SDK).

Only standard headers are sent. No App Check. No SSL pinning. No device/client signing beyond the ID token.

Endpoint path pattern

POST https://api.stafftraveler.com/v1/commands/user/<commandName>

Note the user/ segment — the api_commands_url Remote Config value is https://api.stafftraveler.com/v1/commands/user, and the command name is appended with /. I initially documented this as /v1/commands/<cmd> which is wrong.

Files

searchFlightsByRoute_DFW-LAS_*.json

DFW→LAS direct-only search for 2026-04-22.

Request body:

{
  "originIata": "DFW",
  "destinationIata": "LAS",
  "dates": ["2026-04-22"],
  "maxConnections": 0,
  "allowNearbyDepartures": false,
  "allowNearbyArrivals": false,
  "payloadType": "passenger",
  "includeMultipleCarriers": false
}

Response: {payload: {directFlights: [...], connectingFlights: [...], numberOfDiscardedFlights, messages, settingsFilteredCount}}.

Each flight carries three IDs (id, id_v2, id_v3), airline info, local/UTC times, equipment, and a seatsByClass aircraft configuration (NOT current availability — that's a different read path entirely).

Corrections vs the api_doc's initial guesses:

  • stops → actually maxConnections
  • payloadType: "route" → actually "passenger"
  • No origin/destination/date fields — only the *Iata variants + dates array.

createLoadsRequests_AA2178_*.json

Request loads for AA2178 DFW→LAS 2026-04-22.

Request body is a bare JSON array of flight objects (no outer wrapper). Each flight is the complete flight object from the search response with one added field: isPriorityRequest: bool.

Response shape:

{
  "payload": {
    "numberOfRequests": 0,
    "numberOfRequestsPaidFor": 0,
    "numberOfRequestsPaidForPriority": 0,
    "hasSufficientCredits": true,
    "verifiedRequests": [
      {
        "flightId": "AA_2178_DFW_2026_04_22",
        "isExisting": true,
        "isDuplicateForUser": true,
        "isRequestUpdateForUser": false,
        "hasDeparted": false,
        "isCancelled": false,
        "isPriorityRequest": false,
        "hasRecentLoads": false,
        "scheduledFlight": { /* full flight obj */ }
      }
    ]
  }
}

Dedup behavior (important)

On this capture, numberOfRequests: 0 and isDuplicateForUser: true — the server recognized this user had already requested this flight and did NOT charge a credit. Replaying the same createLoadsRequests payload is safe (idempotent).

This means:

  • numberOfRequests is the count of newly created requests in this call.
  • isDuplicateForUser tells you whether the flight already had an open request for this user.
  • No credit is spent on duplicates. Useful for polling the current request state without cost.

hasRecentLoads: false — where loads actually come from

hasRecentLoads is the flag the app uses to decide whether load data is available for display. It's false here because nobody has submitted loads for AA2178 yet. The actual load data (when hasRecentLoads: true) does NOT come through the commands API — it arrives via a Firestore realtime listener on a doc that the user's account has permission to read.

To find the exact Firestore path when a flight has loads, one more capture is needed: tap a flight that already has loads populated, and grab the firestore.googleapis.com/.../Listen/channel traffic. That will show the watched doc path.

Known error shapes

Not captured yet:

  • What happens when you send an invalid flight ID
  • What createLoadsRequests returns when credits are insufficient (hasSufficientCredits: false)
  • What numberOfRequests > 0 responses look like (fresh request, credit actually spent)

Replay safety

To replay any of these:

  1. Grab a fresh token from the app or by re-signing-in.
  2. Swap it into the curl.
  3. For createLoadsRequests, same payload = dedup-safe. Different payload = may charge credits.