Watch-IP

Compare a login location with the previous stored location

A large change in IP-derived location over a short interval can warrant review. POST /v1/risk/check compares a user's current location estimate with the previous stored point and returns distance, elapsed time, implied speed, and a risk classification.

Availability

This endpoint uses the same secret key as IP lookup — there's no separate risk plan, signup, or price. Every check counts as one request against your existing plan's monthly cap, the same pool GET /v1/geo and /v1/lookup* draw from.

Input and secret-key usage

Send a JSON body of userId, ip, and an optional commit boolean (defaults to true) to POST /v1/risk/check with a secret key via Authorization: Bearer YOUR_SECRET_KEY — server-to-server only, never from a browser.

The first observation

A user's first-ever check has no previous location to compare against: it returns risk: "low", impossibleTravel: false, null distance/speed/elapsed values, and a null previousLocation, and — if commit isn't false — stores this observation as the new baseline.

Subsequent observations

Later checks compare the great-circle distance between the previous and current point against the elapsed time to get an implied speed. Below 500 km/h, the result is "low"; between 500 and 900 km/h, "medium" (a real long-haul flight can land near this boundary); above 900 km/h, "high" and impossibleTravel: true.

The commit flag

commit defaults to true. Set it false for a speculative pre-check — for example, ahead of a step-up-authentication decision — that reads the stored baseline without moving it, so a legitimate check doesn't corrupt the user's real location history.

Missing locations

If ip can't be resolved to a latitude/longitude, the endpoint returns a 422 rather than a low-confidence guess.

Retention and deletion

v1 stores exactly one location per (your account, userId) pair — the most recent committed observation — with no automatic expiry; it persists until the next committed check overwrites it, or you delete it yourself with DELETE /v1/risk/baseline (same secret key, doesn't count against your monthly cap). Because it stores a userId-linked location beyond a single request/response cycle, using this endpoint makes Watch-IP a processor of that data on your behalf — see the Data Processing Addendum.

False positives

v1 has no VPN- or datacenter-aware suppression, so fast VPN toggling or ordinary mobile-network IP churn can produce an elevated result. Treat every classification as a raw signal for your own review process, not a final verdict.

Response fields

risk
low, medium, or high, from the implied-speed thresholds above.
impossibleTravel
Boolean shorthand for risk: "high".
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.
previousLocation
country, latitude, longitude, and observedAt for the stored baseline before this call. Null on a user's first-ever check.
currentLocation
country, latitude, and longitude resolved from the ip you supplied on this call.

Pre-check, then commit

Backend cURL

# Speculative check ahead of your own auth decision — doesn't move the baseline.
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", "commit": false}'

# After your own password/2FA verification succeeds, commit the new baseline.
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"}'

commit defaults to true, so the second call above updates the stored baseline; the first, with commit: false, does not.

Frequently asked questions

What happens on the first check?

It always returns risk: "low" with a null previousLocation — there's nothing yet to compare the current location against.

Does it suppress VPN jumps?

No. v1 has no VPN- or datacenter-aware suppression, so switching networks or VPN exits between logins can produce a medium or high result on its own.

Is a high result proof of compromise?

No. It's a raw distance-over-time calculation. Combine it with your own authentication evidence rather than treating it as a standalone verdict.

Can I avoid updating the baseline?

Yes — pass commit: false. The check still runs and returns a result, but the stored location isn't replaced.

How long is the previous location retained?

Indefinitely, until the next committed check for that userId overwrites it — there's no automatic expiry and no delete endpoint in the current implementation.

Related pages