# host.sh API docs: IP geolocation and lookup API overview

> How the host.sh IP lookup API works: endpoints, API tokens, the Bearer header or token= parameter, and free tokenless lookups of your own IP.

The host.sh API answers with JSON about any IPv4 or IPv6 address: approximate location, time zone, ISP, ASN, connection type and flags such as VPN, proxy and Tor. It runs at `https://api.host.sh` (HTTPS only; plain HTTP is redirected) and allows cross-origin requests, so it works from a browser too.

## Endpoints

| Endpoint | What it does | Token |
|---|---|---|
| `GET /v2/lookup/` | Your own IP, or any IP with `ip=` | Not for your own IP |
| `GET /v2/lookup/{ip}` | One address in the path, e.g. `/v2/lookup/8.8.8.8` | Yes |
| `POST /v2/lookup/` | Same as GET, parameters in a JSON or form body | Not for your own IP |
| `POST /v2/lookup/batch/` | Up to 100 addresses in one request | Yes |
| `GET /v2/ip/` | Just your IP address, as text or `{"ip": ...}` | No |
| `GET /v2/openapi.yaml` | The [OpenAPI spec](https://api.host.sh/v2/openapi.yaml) | No |

`https://ipv4.host.sh` serves the same API over IPv4 only, to learn the IPv4 address of a dual-stack client.

- [Lookup](https://www.host.sh/docs/lookup/index.md): one address, its parameters and code examples
- [Batch](https://www.host.sh/docs/batch/index.md): many addresses in one request
- [Response fields](https://www.host.sh/docs/fields/index.md): what every field in the answer means
- [Errors](https://www.host.sh/docs/errors/index.md): every error code and reason the API returns
- [Rate limits](https://www.host.sh/docs/rate-limits/index.md): what is limited and how to retry
- [OpenAPI reference](https://www.host.sh/docs/openapi/index.md): the spec on one page

## Authentication

A token is a secret string that identifies your account. Tokens are invite only for now. With a token you can look up any address and send batch lookups; which sections of the answer you get depends on your token's plan. Send it in one of three ways:

| Where | Example | Works on |
|---|---|---|
| `Authorization: Bearer` header | `-H "Authorization: Bearer YOUR_TOKEN"` | Every endpoint |
| `token` query parameter | `?token=YOUR_TOKEN` | Every endpoint |
| `token` field of a JSON body | `{"token": "YOUR_TOKEN", "ip": "8.8.8.8"}` | `POST /v2/lookup/` |

Prefer the Bearer header. A token in the URL ends up in browser history, proxy logs and shell history, and anyone who has it can use your plan. If a request carries more than one, a JSON body `token` wins over `?token=`, and `?token=` wins over the header. A form body field named `token` is not read as a token.

```sh
curl -H "Authorization: Bearer YOUR_TOKEN" https://api.host.sh/v2/lookup/8.8.8.8
```

An unknown or disabled token, or one without permission for the endpoint, gets `403` with reason `TOKEN_INVALID`. The batch endpoint without a token gets `401` with reason `TOKEN_MISSING`. See [Errors](https://www.host.sh/docs/errors/index.md).

## No token: your own IP

Without a token the API looks up the address the request comes from, for free and with no sign-up:

```sh
curl https://api.host.sh/v2/lookup/
```

This tokenless mode has limits:

- It only looks up your own IP. Asking for another one, with `ip=`, the path form `/v2/lookup/8.8.8.8`, or `ua=` and `al=`, gets `403` with reason `TOKEN_REQUIRED`.
- Batch lookups always need a token.
- It allows 10 requests a minute per IP address, with short bursts of up to 10. Over that the API answers `429` with a `Retry-After` header; see [Rate limits](https://www.host.sh/docs/rate-limits/index.md).
- The answer has the location, ISP, connection and anonymity sections, and the parsed `User-Agent` and `Accept-Language` headers of the request itself. It has no `connection.usage` section.

All the options work in tokenless mode: `fields`, `format=text`, `lang`, `hostname=1`, `pretty=1` and `callback`.

From a terminal there is also `curl host.sh`, which needs no key either: it prints your IP details as flat JSON, and `curl host.sh/ip` or `curl host.sh/city` print one value. `curl host.sh/help` lists the fields.

## Response format

Every answer is UTF-8 JSON (`application/json; charset=utf-8`) unless you ask for `format=text` or JSONP. Values the API doesn't know are `null` rather than left out, so the shape of the answer stays the same from one address to the next. Errors come as an `errors` array with a numeric `code`, a `message`, a machine-readable `reason` and a `detail` sentence:

```json
{"errors":[{"code":403,"message":"Forbidden","reason":"TOKEN_REQUIRED","detail":"Looking up anything but your own IP needs a token"}]}
```
