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
- POST search intent to /v1/ground/search (rail/bus/mixed)
- POST itineraries to /v1/ground/reliability to compute risk distributions
- POST to /v1/ground/rank with your objective preset
- Optionally subscribe to /v1/webhooks for disruption alerts & re-rank triggers
4) Authentication
Authorization: Bearer YOUR_SPYFACE_API_KEY
5) Endpoints
| Method | Endpoint | Purpose |
|---|---|---|
| POST | /v1/ground/search | Search rail/bus itineraries (normalized) |
| POST | /v1/ground/reliability | Compute delay distributions + on-time probabilities |
| POST | /v1/ground/connections | Compute transfer slack & P(miss) per connection |
| POST | /v1/ground/rank | Rank itineraries by objective function (deadline, comfort, price) |
| POST | /v1/ground/alerts | Create monitoring rules (risk thresholds) |
| POST | /v1/events | Send 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 factor | Spyface computation | Example |
|---|---|---|
| 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
| HTTP | Meaning | What to do |
|---|---|---|
| 400 | Invalid request schema | Validate required keys and timezones |
| 401 | Auth failed | Check Bearer token |
| 409 | Duplicate request_id | Use unique request_id per attempt |
| 429 | Rate limited | Retry with exponential backoff |
| 500 | Internal error | Retry 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