Telemetry in. Events and exposure out.
The interface below is being implemented against the validated detector. It is not generally available — access today is through a design partnership, and there are no uptime guarantees.
Authentication
Bearer token on every request. Keys are environment-scoped; a sk_test_ key
returns real computation against your payload but is never metered.
Authorization: Bearer sk_live_...
Score a trip
POST /v1/trips:score — speed in m/s and curvature in 1/m, sampled at a fixed
rate. Curvature may be supplied directly or derived from yaw rate and speed.
{
"fps": 20.0,
"trip_id": "3f9a2c",
"speed_mps": [24.9, 24.9, 24.8, ...],
"curvature_1pm": [0.0021, 0.0019, ...],
"thresholds": {
"harsh_brake_mps2": -3.0,
"harsh_accel_mps2": 3.0,
"hard_corner_mps2": 3.0
}
}
{
"trip_id": "3f9a2c",
"distance_km": 1.047,
"events": [{
"kind": "harsh_brake",
"start_frame": 412,
"end_frame": 441,
"duration_s": 1.45,
"peak_mps2": -4.31,
"mean_speed_mps": 17.2
}],
"rates_per_100km": {
"harsh_brake": 95.5,
"harsh_accel": 0.0,
"hard_corner": 0.0
},
"calibration": "uncalibrated"
}
Every response carries a calibration field. While it reads
uncalibrated, the rates are measurements against a chosen threshold and carry no
validated relationship to loss. We would rather ship that field than let a number be mistaken
for a score.
Parameters
| Field | Type | Default | Notes |
|---|---|---|---|
fps | number | — | Required. Sample rate of the arrays. |
speed_mps | number[] | — | Required. Metres per second. |
curvature_1pm | number[] | — | Required, same length as speed. Positive = right turn. |
smooth_window_s | number | 0.5 | Applied before differentiation. |
min_duration_s | number | 0.2 | Shorter crossings are discarded as noise. |
merge_gap_s | number | 1.0 | Same-kind events closer than this merge. |
min_corner_speed_mps | number | 5.0 | Below this, cornering is parking. |
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | length_mismatch | speed and curvature arrays differ in length. |
| 400 | implausible_curvature | Implied lateral acceleration exceeds what tyres can deliver — usually a steering angle sent as curvature. |
| 401 | invalid_key | Missing or unrecognised bearer token. |
| 422 | trip_too_short | Fewer than two samples; nothing to differentiate. |
| 429 | rate_limited | Retry after the interval in the response header. |
implausible_curvature is a deliberate hard failure rather than a warning. Wrong
units there produce event counts that look merely high, which is far more dangerous than a
rejected request.
Run it in your own environment
The detector is a small pure-Python library with no service dependency, for partners who would rather not send telemetry anywhere.
from wahanx.risk import events as E cfg = E.EventConfig(fps=20.0, harsh_brake_mps2=-3.0) ev = E.detect_events(trip_df, cfg) # columns: sequence_id, frame_idx, speed, curvature km = E.exposure_km(trip_df, cfg) E.summarise(ev, km) # {'harsh_brake_per_100km': 24.4, 'hard_corner_per_100km': 39.3, ...}