Skip to main content

AI Rail & Bus Intelligence API

Technical Docs Delay-Risk Scoring Multi-Modal Optimization Personalized Ranking
Operated by Spyface Tech Company, LLC • 30 N Gould St Ste N, Sheridan, WY 82801 USA • Support: hello@spyface.com

What this API does

AI Rail & Bus Intelligence API turns ground schedules into a measurable reliability + arrival probability problem. It normalizes rail/bus itineraries and produces: delay-risk distributions (not “on time / late”), missed-connection probability, and traveler-fit ranking under constraints (time windows, accessibility, comfort, price caps).

Legacy APIs stop at “here are trains/buses”. Spyface answers: Which itinerary will actually get this traveler/patient to the appointment on time—under uncertainty?

Primary outputs

  • Delay distribution per segment (P50/P90)
  • Connection risk (P(miss) for each transfer)
  • Itinerary on-time probability vs deadline
  • Reliability score (operator/route/time regime)
  • Ranked results + explanation codes (audit-ready)

1) Overview

Rail and bus planning fails in production for one reason: uncertainty. A schedule is deterministic; operations are not. Spyface models itineraries as a chain of random variables: segment travel time, station dwell variance, and connection slack. The API returns probabilities you can automate on: “Will the traveler make the transfer?” and “Will arrival beat the deadline?”

2) Use Cases

Travel / OTA / Super-app

  • Rank itineraries by P(arrive before check-in) instead of cheapest
  • Automatically avoid “tight” transfers that look good on paper
  • Explain why option #1 is safer (trust = conversion)

Medical Tourism / Appointment-critical

  • Enforce clinic arrival SLA with tail-risk controls (P90)
  • Accessibility-first routing (step-free, minimal walking, elevator reliability)
  • Fallback alternatives & alerts when risk crosses thresholds

3) Quickstart

  1. POST search intent to /v1/ground/search (rail/bus/mixed)
  2. POST itineraries to /v1/ground/reliability to compute risk distributions
  3. POST to /v1/ground/rank with your objective preset
  4. Optionally subscribe to /v1/webhooks for disruption alerts & re-rank triggers

4) Authentication

Authorization: Bearer YOUR_SPYFACE_API_KEY

5) Endpoints

MethodEndpointPurpose
POST/v1/ground/searchSearch rail/bus itineraries (normalized)
POST/v1/ground/reliabilityCompute delay distributions + on-time probabilities
POST/v1/ground/connectionsCompute transfer slack & P(miss) per connection
POST/v1/ground/rankRank itineraries by objective function (deadline, comfort, price)
POST/v1/ground/alertsCreate monitoring rules (risk thresholds)
POST/v1/eventsSend outcomes for calibration (actual delay, missed connection)

6) Reliability Model

What “reliability” means here (operationally)

  • Segment delay distribution: expected + tail delays (P50/P90)
  • Station variability: dwell-time and platform-change penalties
  • Operator regime: time-of-day/week patterns, seasonal patterns, known hotspots
  • Itinerary risk: compounded risk across segments and transfers

The outputs are designed for automation: you can set policies like “Reject itineraries with P(miss transfer) > 0.08” or “Select option with max P(arrive before deadline) subject to max price”.

7) Connection & Transfer Risk

Most itinerary engines treat “connection time” as minutes on a clock. Real-world transfers require: platform change time, walking time distribution, mobility constraints, and station layout penalties.

Transfer factorSpyface computationExample
Minimum connection time Station + operator MCT baseline + dynamic penalties Terminal platforms vs cross-station walk
Mobility/accessibility Elevator dependence, step-free routing, slower walking distribution Wheelchair: +8–15 min transfer distribution shift
Propagation Upstream delay distribution mapped onto connection slack P(miss) computed by convolution of distributions

8) Ranking Objective (No Buzzwords)

Ranking is a deterministic policy layer. The “AI” produces measurable probabilities; the ranker enforces your rules.

// Conceptual score (example)
score(itinerary) =
  w1 * P_arrive_before_deadline
+ w2 * reliability_score
- w3 * normalized_price
- w4 * walking_burden
- w5 * missed_connection_risk

Presets

  • ON_TIME_FIRST: maximize arrival probability
  • BEST_VALUE: balance price vs reliability
  • LOW_TRANSFER_RISK: aggressively avoid tight transfers
  • MEDICAL_READY: low walking + accessibility + low tail risk

Explanation codes

  • TRANSFER_SLACK_STRONG
  • TAIL_DELAY_HIGH
  • WALKING_BURDEN_LOW
  • ARRIVAL_PROBABILITY_HIGH

9) Schemas

9.1 Search Request (Rail + Bus Mixed)

{
  "request_id": "req_20260125_ground_search_72d",
  "origin": {"name":"City A", "lat": 41.015, "lng": 28.979},
  "destination": {"name":"City B", "lat": 40.983, "lng": 29.023},
  "departure_local": "2026-03-12T08:30:00+03:00",
  "modes": ["RAIL","BUS","MIXED"],
  "constraints": {
    "arrive_by_local": "2026-03-12T13:30:00+03:00",
    "max_transfers": 2,
    "max_price": {"amount": 85, "currency": "USD"}
  },
  "traveler": {
    "party_size": 1,
    "accessibility": {"step_free": true},
    "preferences": {"quiet": true, "avoid_overnight": true}
  }
}

9.2 Search Response (Normalized Itineraries)

{
  "request_id":"req_20260125_ground_search_72d",
  "currency":"USD",
  "itineraries":[
    {
      "itinerary_id":"it_1",
      "segments":[
        {
          "mode":"RAIL",
          "operator":"RailCo",
          "from":"STA_A",
          "to":"STA_X",
          "depart_local":"2026-03-12T08:45:00+03:00",
          "arrive_local":"2026-03-12T10:05:00+03:00"
        },
        {
          "mode":"BUS",
          "operator":"BusCo",
          "from":"STA_X",
          "to":"STA_B",
          "depart_local":"2026-03-12T10:35:00+03:00",
          "arrive_local":"2026-03-12T12:55:00+03:00"
        }
      ],
      "pricing":{"total":62.00},
      "raw":{"provider_ref":"P-11819"}
    }
  ]
}

9.3 Reliability Response (Distributions)

{
  "request_id":"req_20260125_ground_rel_19b",
  "itinerary_id":"it_1",
  "segment_delay_minutes":[
    {"segment_index":0,"p50":4,"p90":16},
    {"segment_index":1,"p50":7,"p90":28}
  ],
  "connection_risk":[
    {"at_stop":"STA_X","transfer_minutes_scheduled":30,"transfer_minutes_required_p90":18,"p_miss":0.05}
  ],
  "itinerary_eta_minutes":{"p50": 250, "p90": 310},
  "arrival_probability_by_deadline": 0.91,
  "reliability_score": 0.84,
  "explanations":[
    {"code":"TRANSFER_SLACK_STRONG","detail":"Scheduled transfer exceeds p90 required by 12 minutes"},
    {"code":"OPERATOR_REGIME_STABLE","detail":"Low tail delays for RailCo on this time window"}
  ]
}

10) Code Examples

10.1 cURL — Search

curl -X POST "https://api.spyface.com/v1/ground/search" \
  -H "Authorization: Bearer YOUR_SPYFACE_API_KEY" \
  -H "Content-Type: application/json" \
  -d @ground-search.json

10.2 Python — Reliability + Ranking

import os, requests

API = "https://api.spyface.com"
H = {"Authorization": f"Bearer {os.environ['SPYFACE_API_KEY']}",
     "Content-Type": "application/json"}

# 1) Search
search = requests.post(f"{API}/v1/ground/search", headers=H, json=payload, timeout=15).json()
itins = search["itineraries"]

# 2) Reliability
rel = requests.post(f"{API}/v1/ground/reliability", headers=H, json={
  "request_id":"req_rel_001",
  "arrive_by_local": payload["constraints"]["arrive_by_local"],
  "itineraries": itins
}, timeout=15).json()

# 3) Rank
rank = requests.post(f"{API}/v1/ground/rank", headers=H, json={
  "request_id":"req_rank_001",
  "preset":"LOW_TRANSFER_RISK",
  "arrive_by_local": payload["constraints"]["arrive_by_local"],
  "items": rel["items"]
}, timeout=15).json()

best = rank["results"][0]
print("Best itinerary:", best["itinerary_id"])
print("P(on-time):", best["arrival_probability_by_deadline"])
print("Why:", [e["code"] for e in best["explanations"]])

10.3 Node.js — Connection Risk Gate

import fetch from "node-fetch";

const gate = (r) => r.connection_risk.every(c => c.p_miss <= 0.08);

const res = await fetch("https://api.spyface.com/v1/ground/reliability", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SPYFACE_API_KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ request_id:"req_rel_gate", itineraries })
});
const data = await res.json();
const safe = data.items.filter(gate);

console.log("Safe itineraries:", safe.map(x => x.itinerary_id));

11) Operations (Re-rank & Alerts)

Production pattern: continuous risk monitoring

  • Create alert: “If P(arrive) drops below 0.80, notify & recommend alternatives.”
  • Re-rank when upstream signal changes (station disruption, operator notice, timetable update).
  • For appointment-critical flows, keep a “backup itinerary set” precomputed.
{
  "rule_id":"rule_arrival_floor",
  "when":{"arrival_probability_below":0.80},
  "then":{"action":"WEBHOOK","event":"ground.risk_threshold_breached"}
}

12) Errors

HTTPMeaningWhat to do
400Invalid request schemaValidate required keys and timezones
401Auth failedCheck Bearer token
409Duplicate request_idUse unique request_id per attempt
429Rate limitedRetry with exponential backoff
500Internal errorRetry once; contact support if persistent

13) Security

  • Send minimal traveler data. Prefer pseudonymous IDs.
  • Optional enterprise: IP allowlist, scoped keys, HMAC signing.
  • Do not transmit payment credentials; keep PCI scope outside this API.

High-leverage step (makes you better than competitors)

Feed outcomes back: actual arrival delay, missed connections, and station transfer times. Calibration improves tail-risk accuracy dramatically, which is where real money is (support tickets, refunds, SLA misses). For integration support: hello@spyface.com