> ## Documentation Index
> Fetch the complete documentation index at: https://docs.veilroute.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# HTTP client & TLS

> Match your client's TLS fingerprint to the sensor, or Akamai blocks you anyway.

Akamai inspects your **TLS handshake** (the ClientHello) before it ever reads the request body. A
default HTTP client — Python `requests`, Node `fetch`/`axios`, Go `net/http` — has a fingerprint
(JA3/JA4) that no real browser or app produces, so the request is flagged **even with a valid
sensor**. The sensor and the TLS fingerprint have to tell the same story.

## Match the fingerprint to the product

> **Akamai Web**
>
> Impersonate a recent **Chrome** desktop. The web sensor models a browser, so your TLS and headers
> must look like that browser.

> **Akamai BMP (mobile)**
>
> Impersonate the Android **OkHttp** client. The mobile sensor models the SDK, so a Chrome
> fingerprint here is a mismatch.

## Libraries

Use an HTTP client that lets you set the TLS fingerprint:

| Language | Library | Notes |
| - | - | - |
| Python | `tls-client` | `pip install tls-client`. Chrome **and** OkHttp profiles. |
| Python | `curl_cffi` | `impersonate="chrome"`. Browser only — no OkHttp profile. |
| Go | `github.com/bogdanfinn/tls-client` | Chrome and OkHttp profiles, or `utls` directly. |
| Node | `tlsclientwrapper` | Wraps the bogdanfinn tls-client. |

Use the **newest Chrome profile** your library ships for Web, and an **OkHttp Android** profile for
BMP.

## Akamai Web — Chrome

Generate the sensor, then send your own request with a Chrome fingerprint, through your proxy:

```python Python (tls-client) theme={null}
import os, tls_client, requests

key = os.environ["VEILROUTE_KEY"]

# 1. Sensor from VeilRoute
sensor = requests.post(
    "https://web.veilroute.dev/api/v1/sensor",
    headers={"X-Api-Key": key},
    json={"cookies": "_abck=...; bm_sz=..."},
    timeout=30,
).json()["sensor_data"]

# 2. Your request, Chrome TLS, your proxy, pinned header order
session = tls_client.Session(
    client_identifier="chrome_133",
    random_tls_extension_order=True,
)
session.proxies = {"https": os.environ["PROXY"]}
resp = session.post(
    "https://www.target.com/path",
    data={"sensor_data": sensor},
    header_order=["host", "user-agent", "accept", "accept-language", "cookie"],
    headers={
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
        "accept-language": "pt-BR,pt;q=0.9",
    },
)
```

```go Go (bogdanfinn/tls-client) theme={null}
import (
    tls_client "github.com/bogdanfinn/tls-client"
    "github.com/bogdanfinn/tls-client/profiles"
)

client, _ := tls_client.NewHttpClient(tls_client.NewNoopLogger(),
    tls_client.WithClientProfile(profiles.Chrome_133),
    tls_client.WithProxyUrl(os.Getenv("PROXY")),
)
// POST sensor_data to the target with Chrome headers in browser order
```

## Akamai BMP — OkHttp

The target here is a mobile API, so impersonate the app's OkHttp client:

```python Python (tls-client) theme={null}
import os, tls_client, requests

key = os.environ["VEILROUTE_KEY"]
sensor = requests.post(
    "https://bmp.veilroute.dev/api/v1/sensor",
    headers={"X-Api-Key": key},
    json={"app": "com.example.app"},
    timeout=30,
).json()["sensor"]

session = tls_client.Session(client_identifier="okhttp4_android_13")
resp = session.get(
    "https://api.target.com/mobile/endpoint",
    headers={
        "x-acf-sensor-data": sensor,
        "user-agent": "okhttp/4.12.0",
        "accept": "application/json",
    },
)
```

> [!NOTE]
>
> The BMP sensor is **not tied to an IP**, so you can send it from any proxy. What has to match is the
> **OkHttp/Android** fingerprint plus the app's own headers and User-Agent.

## Pin the header order

Akamai reads the **order** of your headers, not just their values. Send them in the exact order the
real browser (Web) or app (BMP) uses. `tls-client` exposes `header_order`; `curl_cffi` keeps the
order of the dict you pass. Base the order on a real capture of Chrome or the app.

## Proxy

* **Web:** generate the sensor and send the request from the **same clean session and IP**. Use a
  sticky residential proxy and keep the region and `Accept-Language` consistent with that IP.
* **BMP:** any proxy works (IP-independent), but a residential IP in the app's expected region is
  still the safest choice.

## One client per identity

Keep one cookie jar, User-Agent and proxy per logical session. Don't share a cookie jar across IPs,
and tear sessions down cleanly at shutdown.

## Verify your fingerprint

Point your client at a JA3/JA4 echo service — for example `https://tls.peet.ws/api/all` — and confirm
the fingerprint matches the Chrome or OkHttp profile you intended, before you spend time debugging
anything on the target side.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.