Watch-IP

Impossible Travel Detection API Reference

POST/v1/risk/check

Compares a supplied IP's location against a stored per-user baseline and classifies the implied travel speed. A raw signal for your own fraud workflow, not a final verdict. There's no separate risk plan or price — each check counts as one request against your existing plan's monthly cap, the same secret key you already use for IP lookup.

Authentication

Provide a secret key via Authorization: Bearer YOUR_SECRET_KEY, the same key type as the lookup endpoints. Send a JSON body of userId, ip, and an optional commit boolean (defaults to true; set false for a speculative check that shouldn't move the stored baseline). To delete a stored baseline, call DELETE /v1/risk/baseline with a JSON body of userId — same auth, doesn't count against your monthly cap, and is idempotent if no baseline exists.

Response fields

risk
low, medium, or high.
impossibleTravel
Boolean shorthand for whether the implied speed between the previous and current location exceeds a plausible travel speed.
distanceKm, impliedSpeedKmh, elapsedSeconds
The distance and time between the previous and current observation, and the speed that implies. Null on a user's first-ever check, when there's no previous location to compare against.
previousLocation
country, latitude, longitude, and observedAt for the stored baseline before this call. Null when this is the first-ever check for this userId.
currentLocation
country, latitude, and longitude for the ip you supplied on this call.

Errors

400
Malformed IP address or missing userId.
401
Missing or invalid API key.
403
A publishable key was used instead of a secret key.
422
The supplied IP could not be resolved to a location.
429
The per-minute rate limit or the plan's monthly request cap has been exceeded — see errors and rate limits for how to tell which.

Example

Request

curl https://api.watch-ip.com/v1/risk/check \
  -H "Authorization: Bearer YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"userId": "u_123", "ip": "203.0.113.1"}'

Response

{
  "risk": "high",
  "impossibleTravel": true,
  "distanceKm": 8843.2,
  "impliedSpeedKmh": 4421.6,
  "elapsedSeconds": 7200,
  "previousLocation": { "country": "FR", "latitude": 48.8566, "longitude": 2.3522, "observedAt": "2026-09-06T12:00:00.000Z" },
  "currentLocation": { "country": "US", "latitude": 30.2672, "longitude": -97.7431 }
}

Limits

v1 stores only the single most-recent location per user, not a history window — expect false positives from fast VPN-toggling or mobile-network IP churn, since there's no VPN/datacenter-aware suppression yet. Treat the result as a raw signal, not a final verdict. Because this endpoint stores a userId-linked location beyond a single request/response cycle, using it makes Watch-IP a processor of that data on your behalf — see the Data Processing Addendum, and DELETE /v1/risk/baseline above for how to fulfill a deletion request.

Related pages