Standard status codes, a stable code in the body, and a plain next step for each.
{ "error": "quota_exhausted", "quota": 2000, "used": 2000 }The error field is the stable identifier to branch on. Some errors add fields: 402 carries the quota and what was used, 429 carries a reset time, 400 for a batch carries the maximum size.
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 401 | invalid_key | The key is missing, malformed, or revoked. | Check the Authorization header and the key on your account page. Revoked keys stop on the next request. |
| 402 | quota_exhausted | This month's lookups are spent. | Wait for the first of the month, or add a pack from the account page. The API never throttles silently. |
| 429 | rate_limited | Too many requests this minute for your plan. | Back off until the reset time in the body, then retry. |
| 404 | not_found | We do not hold that domain or technology. | Nothing to retry. The lookup is still spent for domain calls. |
| 400 | bad_domain | We could not read a hostname out of what you sent. No lookup was spent. | Send a hostname or a URL. We drop the scheme, path, port and a leading www. before the lookup, so https://www.acme.com/about and acme.com are the same request. |
| 400 | bad_host | Same as bad_domain: nothing hostname-shaped in the input. No lookup was spent. | Same rule as bad_domain. |
| 400 | bad_batch | The body is not {"domains": [...]} with 1 to 100 entries we can read as hostnames. No lookup was spent. | Send a JSON body with a domains array of at most 100 hostnames or URLs. The response names up to ten entries we could not read, in an invalid array. |
| 503 | metering_unavailable | The quota could not be read, so nothing was served. | Retry in a moment. No lookup was spent. |