Watch-IP

Errors and rate limits

Every Watch-IP endpoint returns errors in the same shape and enforces rate limits the same way, regardless of which product you're calling.

Error response shape

A non-2xx response is always a JSON object with error (a stable machine-readable code) and message (a human-readable description). error stays constant across API versions; message text may change, so match on error, not on message.

Error response

{
  "error": "invalid_ip",
  "message": "\"999.999.999.999\" is not a valid IPv4 or IPv6 address."
}

Common status codes

The exact set of codes an endpoint can return is documented on its own reference page; these are the ones shared across the API.

400
Malformed input — an invalid IP address, an empty or oversized batch (POST /v1/lookup allows up to 100 IPs), or a missing required field.
401
Missing or invalid API key.
403
Wrong key type for this route (a publishable key on a secret-key endpoint, or vice versa), or — for GET /v1/geo and POST /v1/email/validate only — an Origin/Referer not on the key's allowed-origins list. In the origin case, no CORS header is set either, so the browser blocks the response regardless of this body.
422
Semantically valid input that can't be processed — currently only POST /v1/risk/check, when the supplied IP can't be resolved to a location.
429
Either the per-minute rate limit or the plan's monthly request cap has been exceeded — see error for which (rate_limit_exceeded vs. monthly_limit_exceeded), since only one of them clears on its own within the next minute.

Rate limits

Rate limits are enforced per customer account on a fixed one-minute window, shared across every endpoint you call rather than tracked per route. The limit counts HTTP calls, not items: POST /v1/lookup and POST /v1/email/batch count as one request whether they carry 1 or 100 entries, as do creating, polling and downloading an email list job. A rate-limit 429 (error: "rate_limit_exceeded") includes a Retry-After header giving the number of seconds until the current window resets — wait that long, then retry.

Monthly request caps

Separately from the per-minute rate limit, every plan has a monthly request cap that's enforced in real time, not just reported after the fact: once a key's account reaches it, further requests are rejected with a 429 and error: "monthly_limit_exceeded" until the next monthly window starts or the plan is upgraded. POST /v1/lookup's batch is checked and rejected as a whole against the remaining cap — never partially fulfilled. You'll receive an email at 75%, 90%, and 100% of your cap so this shouldn't be a surprise mid-integration.

Retrying safely

GET /v1/geo, GET /v1/lookup/{ip}, POST /v1/lookup, and POST /v1/email/validate are read-only and safe to retry immediately after a network error. POST /v1/risk/check updates a stored baseline by default — pass commit:false first if you need a speculative retry that shouldn't move it.

Related pages