AI Cars & Transfers API
Technical Docs
Ground Transport Intelligence
ETA Confidence + Matching
Risk & Dispatch Scoring
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 Cars & Transfers API provides an AI decision layer for ground transport: ETA prediction with confidence, vehicle-context matching, and cost–comfort–reliability scoring for rides, airport transfers, and chauffeur services.
Classic transfer APIs return “a list of cars”. Spyface returns ranked options plus arrival-risk and service-fit, so you can automate the “right car for this traveler” decision instead of guessing.
Primary outputs
- ETA (P50/P90) and on-time probability per option
- Pickup feasibility (zone rules, curb constraints, airport regimes)
- Vehicle match score (bags, party size, special needs)
- Reliability score (provider, route, time-of-day)
- Ranking with explanation codes (audit-ready)
1) Overview
Ground transport looks simple until you operate at scale: airport pickup regimes, curb restrictions, event traffic, provider reliability variance, and “last mile” timing chains with flights/hotels. Spyface models transfers as a probabilistic arrival problem: not “ETA = 42 min”, but “ETA distribution + confidence + best option under constraints”.
2) Use Cases
Travel / OTA / TMC
- Rank transfer options by on-time probability to meet flight check-in windows
- Offer “best value” vs “premium reliability” choices with transparent reasons
- Prevent oversell: block options with low pickup feasibility at the airport
Medical Tourism
- Patient-ready transfers: accessibility constraints + comfort scoring
- Clinic arrival SLA: combine flight disruption risk + ground ETA distribution
- Risk flags: driver no-show likelihood and recovery routing
3) Quickstart
- POST trip + traveler constraints to /v1/transfers/quote
- POST returned options to /v1/transfers/rank
- Confirm with /v1/transfers/book (optional) + subscribe to webhooks
4) Authentication
Authorization: Bearer YOUR_SPYFACE_API_KEY
5) Endpoints
| Method | Endpoint | Purpose |
|---|---|---|
| POST | /v1/transfers/quote | Get transfer options (provider-agnostic normalized schema) |
| POST | /v1/transfers/eta | Compute ETA distribution (P50/P90) + on-time probability |
| POST | /v1/transfers/match | Validate constraints (bags, pax, mobility) + match score |
| POST | /v1/transfers/rank | Rank options by objective function (reliability/cost/comfort) |
| POST | /v1/transfers/book | Book selected option (optional, if enabled for your account) |
| POST | /v1/webhooks | Subscribe: driver assigned, pickup started, no-show risk, etc. |
| POST | /v1/events | Send outcomes (actual pickup delay, no-show) for calibration |
6) Data Model
6.1 Quote Request (Airport Transfer Example)
{
"request_id": "req_20260125_xfer_91f",
"trip": {
"pickup": {
"type": "AIRPORT",
"iata": "JFK",
"lat": 40.6413,
"lng": -73.7781,
"local_time": "2026-03-12T18:20:00-04:00",
"terminal": "4",
"pickup_mode": "CURB"
},
"dropoff": {
"type": "HOTEL",
"name": "Midtown Hotel",
"lat": 40.7580,
"lng": -73.9855
}
},
"traveler": {
"party_size": 2,
"bags": {"checked": 2, "carry_on": 2},
"accessibility": {"wheelchair": false},
"preferences": {"avoid_shared": true, "quiet_ride": true}
},
"constraints": {
"latest_arrival_local": "2026-03-12T19:45:00-04:00",
"max_price_usd": 160,
"min_vehicle_class": "STANDARD"
}
}
6.2 Quote Response (Normalized Options)
{
"request_id": "req_20260125_xfer_91f",
"currency": "USD",
"options": [
{
"option_id": "opt_1",
"provider": {"name":"ProviderA","service_level":"chauffeur"},
"vehicle": {"class":"STANDARD","seats":3,"bags_capacity":4},
"pricing": {"total": 98.50, "includes_tolls": true},
"policy": {"free_wait_minutes_airport": 45},
"raw": {"provider_ref": "A-99181"}
},
{
"option_id": "opt_2",
"provider": {"name":"ProviderB","service_level":"rideshare"},
"vehicle": {"class":"PREMIUM","seats":3,"bags_capacity":3},
"pricing": {"total": 132.00, "includes_tolls": false},
"policy": {"free_wait_minutes_airport": 10},
"raw": {"provider_ref": "B-77120"}
}
]
}
6.3 ETA Response (Distribution + Confidence)
{
"request_id": "req_20260125_eta_3a2",
"option_id": "opt_1",
"eta_minutes": {"p50": 44, "p90": 63},
"on_time_probability": 0.86,
"pickup_feasibility": {"score": 0.92, "regime": "AIRPORT_CURB_OK"},
"risk_flags": ["EVENT_TRAFFIC_MODERATE"],
"explanations": [
{"code":"AIRPORT_BUFFER", "detail":"Airport pickup adds predictable curb/exit delay"},
{"code":"TRAFFIC_REGIME", "detail":"Time-of-day congestion elevated vs baseline"}
]
}
7) ETA & On-time Model (Measurable)
Spyface does not ship a single “ETA number”. We ship a distribution. If your SLA requires arrival by a deadline, the only honest question is: P(arrive before deadline).
Key outputs
- p50: median ETA (typical case)
- p90: stress ETA (tail risk)
- on_time_probability: P(arrive ≤ deadline) or P(pickup ≤ wait window)
- calibration band (optional): how reliable the probability is in this regime
If your UI shows “ETA 44 min”, you will lose trust on bad days. If you show “44–63 min (90%)” + on-time probability, you can automate decisions safely.
8) Vehicle Matching (Constraints)
Matching is not a marketing filter; it’s a hard feasibility check. Bags and accessibility constraints are frequent failure points in transfers.
| Constraint | What Spyface checks | Example failure prevented |
|---|---|---|
| Capacity | Seats + bag volume (checked/carry-on) + stroller/medical equipment | “2 pax + 4 bags” sent to a sedan (pickup chaos) |
| Accessibility | Wheelchair support / step height / loading time penalties | Patient readiness: vehicle cannot safely board |
| Pickup regime | Airport curb rules, commercial lanes, zone restrictions | Driver cannot legally enter terminal curb area |
| Timing | Wait windows, buffer for baggage claim, terminal exit time distributions | Driver leaves early → no-show or extra fees |
9) Ranking Engine (Objective Function)
Ranking is deterministic and auditable. The AI feeds measured probabilities, while the ranker enforces business constraints.
// Conceptual scoring (example)
score(option) =
w1 * on_time_probability
+ w2 * reliability_score
+ w3 * match_score
- w4 * normalized_price
- w5 * operational_risk
Common presets
- BEST_VALUE: maximize on-time with price sensitivity
- PREMIUM_RELIABILITY: minimize tail risk (p90)
- MEDICAL_READY: accessibility + comfort + low volatility
Explanation codes
- CAPACITY_MATCH_STRONG
- AIRPORT_PICKUP_FEASIBLE
- TAIL_RISK_LOW (p90 tight)
- PROVIDER_RELIABILITY_HIGH
10) Risk Signals
Operational risks you can actually act on
- No-show risk (provider/time regime) → auto-escalate backup options
- Pickup complexity (airport/terminal) → add buffer or switch provider
- Traffic regime shift → re-rank in real time if departure/pickup changes
- Price volatility (rideshare) → hedge with fixed-fare chauffeur option
Risk without an action is noise. Spyface returns the action path.
11) Idempotency & Webhooks
Idempotency (important in bookings)
Use Idempotency-Key header for /book to prevent duplicate bookings on retries.
Idempotency-Key: xfer_book_20260312_istjfk_0001
Webhook events (examples)
- transfer.driver_assigned
- transfer.pickup_started
- transfer.no_show_risk_high
- transfer.completed
12) Code Examples
12.1 cURL — Quote
curl -X POST "https://api.spyface.com/v1/transfers/quote" \
-H "Authorization: Bearer YOUR_SPYFACE_API_KEY" \
-H "Content-Type: application/json" \
-d @quote-request.json
12.2 Node.js — Rank Options
import fetch from "node-fetch";
const payload = {
request_id: "req_20260125_rank_19a",
preset: "BEST_VALUE",
deadline_local: "2026-03-12T19:45:00-04:00",
options: optionsFromQuote // normalized options array
};
const res = await fetch("https://api.spyface.com/v1/transfers/rank", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SPYFACE_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
});
if (!res.ok) throw new Error(await res.text());
const data = await res.json();
console.log("Top option:", data.results[0].option_id);
console.log("Why:", data.results[0].explanations.map(e => e.code).join(","));
12.3 Python — ETA With Confidence
import os, requests
resp = requests.post(
"https://api.spyface.com/v1/transfers/eta",
headers={
"Authorization": f"Bearer {os.environ['SPYFACE_API_KEY']}",
"Content-Type": "application/json",
},
json={
"request_id":"req_20260125_eta_3a2",
"option": option, # one option from /quote
"deadline_local":"2026-03-12T19:45:00-04:00",
"context":{"airport":"JFK","terminal":"4","pickup_mode":"CURB"}
},
timeout=10
)
resp.raise_for_status()
eta = resp.json()
print("p50:", eta["eta_minutes"]["p50"], "p90:", eta["eta_minutes"]["p90"],
"P(on-time):", eta["on_time_probability"])
12.4 Outcomes → Calibration (high leverage)
Send actual pickup delay / travel time / no-show outcomes. This improves calibration and tail-risk estimates.
{
"request_id": "req_20260125_xfer_91f",
"events": [
{"type":"OUTCOME_PICKUP_DELAY_MINUTES","value": 12, "ts":"2026-03-12T18:35:00-04:00"},
{"type":"OUTCOME_TRIP_DURATION_MINUTES","value": 49, "ts":"2026-03-12T19:25:00-04:00"},
{"type":"OUTCOME_NO_SHOW","value": false, "ts":"2026-03-12T18:34:00-04:00"}
]
}
13) Errors
| HTTP | Meaning | What to do |
|---|---|---|
| 400 | Invalid schema / missing fields | Validate required keys; use ISO timestamps |
| 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 |
14) Security
- Encrypt in transit (TLS). Do not send raw payment credentials.
- Minimize PII. Use pseudonymous traveler IDs when possible.
- Optional enterprise controls: IP allowlist, HMAC request signing, scoped keys.
Production deployment checklist (fast win)
- Start with /quote → /rank in “assist mode” (UI hints, no automation)
- Track KPI: missed pickup / late arrival, no-show rate, support tickets
- Turn on webhooks + idempotency for bookings
- Send outcomes to improve calibration and tail risk
Want a benchmark plan for your market? Email: hello@spyface.com