Mobile Akamai

Mobile Akamai Sensor Data API

Generate the x-acf-sensor-data header required by Akamai-protected mobile APIs.

Note: Currently only Android devices are supported for sensor data generation. iOS is not supported at this time.

Authentication

All requests require an X-API-Key header.

X-API-Key: your-api-key

Generate Sensor Data

POST/akamai-sensor-data

Request Body

Field Type Required Description
app string Yes Lowercase app name
proxy string No Your proxy URL (protocol://[user:pass@]host:port). Required only for apps that have SDK or SBSD challenge solving enabled — the proxy is used to fetch challenge scripts from the target domain and submit solutions. If the app doesn't use these challenges, sensor data is generated locally and no proxy is needed.

Response Body

Field Description
status"succeeded" or "failed"
sensor_dataEncrypted string to use as the x-acf-sensor-data header
app_versionApp version string matching the target's Akamai SDK config
android_id16-char hex device ID (Settings.Secure.ANDROID_ID)
ro_build_version_releaseAndroid OS version
ro_build_idAndroid build ID
ro_product_manufacturerDevice manufacturer
ro_product_modelDevice model

Success Response (200)

json{
  "status": "succeeded",
  "sensor_data": "6,a,...<encrypted sensor data>",
  "app_version": "9.3.3",
  "android_id": "a3f8c91b2e4d7f06",
  "ro_build_version_release": "16",
  "ro_product_manufacturer": "SAMSUNG",
  "ro_product_model": "SM-S936B",
  "ro_build_id": "AP3A.250405.038"
}

Error Responses

Status Meaning
400Invalid request body or unsupported app name
401Missing or invalid API key
402Insufficient token balance
500Sensor data generation failed (retry)

Examples

Note: We will share the per-app TLS config with you if you have your own TLS proxy. If not, you can use our Mobile TLS Relay. Please note that not using TLS proxy will result in blocked requests even if the sensor data header is valid. Using our built-in TLS proxy for SDK / SBDS requests is mandatory and seamless for the user and cannot be done on user side. SDK / SBSD challenges usage depends on the per-app configuration and cannot be enabled or disabled by the user as it would result in blocked requests.

Node.js

javascriptconst response = await fetch("https://mobile.botpulse.io/akamai-sensor-data", {
  method: "POST",
  headers: {
    "X-API-Key": "your-api-key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    app: "footlocker",
    proxy: "http://user:pass@proxy.example.com:8080",
  }),
});

const data = await response.json();

// data.sensor_data       — use as x-acf-sensor-data header
// data.ro_product_model  — e.g. "SM-S936B"
// data.ro_build_version_release — e.g. "16"

Go

gopackage main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
)

func main() {
    body, _ := json.Marshal(map[string]string{
        "app":   "footlocker",
        "proxy": "http://user:pass@proxy.example.com:8080",
    })

    req, _ := http.NewRequest("POST", "https://mobile.botpulse.io/akamai-sensor-data", bytes.NewReader(body))
    req.Header.Set("X-API-Key", "your-api-key")
    req.Header.Set("Content-Type", "application/json")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    var result struct {
        Status                string `json:"status"`
        SensorData            string `json:"sensor_data"`
        AppVersion            string `json:"app_version"`
        AndroidId             string `json:"android_id"`
        RoBuildVersionRelease string `json:"ro_build_version_release"`
        RoProductManufacturer string `json:"ro_product_manufacturer"`
        RoProductModel        string `json:"ro_product_model"`
        RoBuildId             string `json:"ro_build_id"`
    }
    json.NewDecoder(resp.Body).Decode(&result)

    fmt.Println("Sensor data:", result.SensorData[:50]+"...")
    // Use result.SensorData as the x-acf-sensor-data header
}

Notes

  • Proxy is only required for apps with SDK/SBSD challenges enabled. When needed, the proxy fetches challenge scripts from the target domain and submits solutions. To get best results please don't use datacenter proxies.
  • Proxy ports. Our infrastructure has firewall rules for standard proxy provider ports (Bright Data, etc.). If you use a proxy with a non-standard port, please let us know in advance so we can whitelist it.
  • TLS service fees. SDK and SBSD challenge solving routes requests through our TLS proxy service to match real mobile TLS fingerprints. This incurs additional per-request fees for the TLS service on top of the sensor data generation cost.
  • Single-use. Each call generates a fresh sensor data string with a new random device profile. Generate a new one for each request to the target API.
  • Device consistency. Use the ro_* fields from the response to build all necessary headers (User-Agent, device model, etc.) so they match the generated sensor data. If you need additional device properties included in the response, please contact us.
Mobile TLS Relay

Mobile TLS Relay API

Mobile TLS Relay forwards your HTTP requests through your proxy while applying a real mobile app TLS fingerprint. This makes requests appear as if they come from a real mobile device.

Authentication

All requests require an X-API-Key header.

X-API-Key: your-api-key

Relay Request

POST/relay

Sends an HTTP request through a proxy with the correct mobile TLS fingerprint. The TLS fingerprint is automatically selected based on the target URL's hostname. Sessions are managed automatically — a persistent TLS connection is created on the first request and reused for subsequent requests with the same hostname + proxy combination. Sessions are automatically destroyed after 1 minute of inactivity.

Request Body

Field Type Required Description
proxy string Yes Your proxy URL (protocol://[user:pass@]host:port)
method string Yes HTTP method (GET, POST, PUT, DELETE, etc.)
url string Yes Full target URL
headers object Yes Request headers as key-value pairs
body string No Request body string (for POST/PUT). Stringify JSON before passing.
unique_id string No Optional identifier to isolate parallel sessions. Use different values when you need multiple independent sessions simultaneously.

Response Body

Field Description
statusHTTP status code from the target server
headersResponse headers from the target server
bodyResponse body as a string

Success Response (200)

json{
  "status": 200,
  "headers": {
    "content-type": "application/json",
    "server": "nginx"
  },
  "body": "{\"data\": \"response from target\"}"
}

Error Responses

Status Meaning
400Invalid request body or unsupported hostname
401Missing or invalid API key
402Insufficient token balance
500Relay failed (proxy error, connection timeout, etc.)

Examples

Node.js

javascriptconst TLS_URL = "https://ctls.botpulse.io";
const API_KEY = "your-api-key";
const PROXY = "protocol://[user:pass@]host:port";

// GET request
const response = await fetch(`${TLS_URL}/relay`, {
  method: "POST",
  headers: {
    "X-API-Key": API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    proxy: PROXY,
    method: "GET",
    url: "https://api.footlocker.com/v4/search",
    headers: {
      "User-Agent": "Footlocker/9.3.3 okhttp/4.12.0 Android/16",
      "Accept": "application/json",
    },
  }),
});

const { status, headers, body } = await response.json();
console.log(`Target responded with ${status}`);

// POST request (same session is reused automatically)
const response2 = await fetch(`${TLS_URL}/relay`, {
  method: "POST",
  headers: {
    "X-API-Key": API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    proxy: PROXY,
    method: "POST",
    url: "https://api.footlocker.com/v4/cart",
    headers: {
      "User-Agent": "Footlocker/9.3.3 okhttp/4.12.0 Android/16",
      "Content-Type": "application/json",
      "Accept": "application/json",
    },
    body: JSON.stringify({ sku: "12345", size: "10" }),
  }),
});

Go

gopackage main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
)

func main() {
    tlsURL := "https://ctls.botpulse.io"
    apiKey := "your-api-key"
    proxy := "protocol://[user:pass@]host:port"

    payload, _ := json.Marshal(map[string]interface{}{
        "proxy":  proxy,
        "method": "GET",
        "url":    "https://api.footlocker.com/v4/search",
        "headers": map[string]string{
            "User-Agent": "Footlocker/9.3.3 okhttp/4.12.0 Android/16",
            "Accept":     "application/json",
        },
    })

    req, _ := http.NewRequest("POST", tlsURL+"/relay", bytes.NewReader(payload))
    req.Header.Set("X-API-Key", apiKey)
    req.Header.Set("Content-Type", "application/json")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    var result struct {
        Status  int               `json:"status"`
        Headers map[string]string `json:"headers"`
        Body    string            `json:"body"`
    }
    json.NewDecoder(resp.Body).Decode(&result)

    fmt.Printf("Target responded with %d\n", result.Status)
}

Notes

  • Automatic sessions. You don't need to manage sessions. The service automatically creates a persistent TLS connection on the first request for a given hostname + proxy combination and reuses it for subsequent requests. Sessions are destroyed after 1 minute of inactivity.
  • TLS fingerprinting. The correct mobile app TLS fingerprint is automatically selected based on the target URL's hostname. You don't need to configure anything.
  • Header ordering. Headers you pass in the headers field will be sent in the wire order configured for the target domain, not alphabetically. Just pass the headers you need.
  • Proxy ports. Our infrastructure has firewall rules for standard proxy provider ports (Bright Data, etc.). If you use a proxy with a non-standard port, please let us know in advance so we can whitelist it.
Fastly

Fastly Challenge Solver API

Solve Fastly _fs-ch challenges and receive bypass cookies ready to use in your requests.

Authentication

All requests (except GET /ping) require an API key via the X-API-Key header:

X-API-Key: your-api-key

Requests without a valid key receive a 401 Unauthorized response.

Solve Challenge

POST/f

Request

Send a JSON body with the target URL and proxy:

bashcurl -X POST https://api.botpulse.io/f \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-api-key" \
  -d '{"input": {"url": "https://example.com/search?q=test", "proxy": "http://user:pass@proxy.example.com:8080"}}'
json{
  "input": {
    "url": "https://example.com/search?q=test",
    "proxy": "http://user:pass@proxy.example.com:8080"
  }
}

Fields

Field Type Required Description
input.url string Yes The full URL of the page protected by Fastly's challenge. Must be a valid URL.
input.proxy string Yes Your proxy URL (protocol://[user:pass@]host:port). The proxy is used to fetch the challenge page and scripts from the target domain, perform the PAT handshake, and submit solutions. All outbound requests to the target go through this proxy.

Response

Success (HTTP 200)

json{
  "status": "succeeded",
  "result": {
    "cookies": [
      "_fs_ch_session=abc123",
      "_fs_ch_exp=1760394626"
    ]
  }
}
Field Type Description
statusstringAlways "succeeded" on success.
result.cookiesstring[]List of Fastly bypass cookies in name=value format.

Failure (HTTP 400)

json{
  "status": "failed",
  "error": "Could not find Fastly script ID in initial page"
}
Field Type Description
statusstringAlways "failed" on failure.
errorstringSpecific error describing what went wrong.

Unauthorized (HTTP 401)

json{
  "status": "failed",
  "error": "Unauthorized"
}

Returned when the X-API-Key header is missing or invalid.


Using the cookies

Attach the returned cookies to subsequent requests to the target site using the Cookie header:

Cookie: _fs_ch_session=abc123; _fs_ch_exp=1760394626

cURL

bash# Step 1: Solve the challenge
RESPONSE=$(curl -s -X POST https://api.botpulse.io/f \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-api-key" \
  -d '{"input": {"url": "https://example.com/search?q=test", "proxy": "http://user:pass@proxy.example.com:8080"}}')

# Step 2: Extract cookies (requires jq)
COOKIES=$(echo "$RESPONSE" | jq -r '.result.cookies | join("; ")')

# Step 3: Make a request with the cookies
curl -s "https://example.com/search?q=test" \
  -H "Cookie: $COOKIES"

Python

pythonimport requests

# Step 1: Solve the challenge
response = requests.post(
    "https://api.botpulse.io/f",
    headers={"X-API-Key": "your-api-key"},
    json={
        "input": {
            "url": "https://example.com/search?q=test",
            "proxy": "http://user:pass@proxy.example.com:8080",
        }
    },
)
data = response.json()

# Step 2: Use the cookies
cookies = {}
for cookie in data["result"]["cookies"]:
    name, value = cookie.split("=", 1)
    cookies[name] = value

# Step 3: Make a request with the cookies
page = requests.get("https://example.com/search?q=test", cookies=cookies)
print(page.text)

Node.js

javascript// Step 1: Solve the challenge
const response = await fetch("https://api.botpulse.io/f", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": "your-api-key",
  },
  body: JSON.stringify({
    input: {
      url: "https://example.com/search?q=test",
      proxy: "http://user:pass@proxy.example.com:8080",
    },
  }),
});
const data = await response.json();

// Step 2: Use the cookies
const cookieHeader = data.result.cookies.join("; ");

// Step 3: Make a request with the cookies
const page = await fetch("https://example.com/search?q=test", {
  headers: { Cookie: cookieHeader },
});

Error cases

The error field contains a specific message describing what failed:

Scenario HTTP Status Example error value
Missing or invalid API key401"Unauthorized"
Invalid or missing fields400Validation error details
No Fastly challenge found on page400"Could not find Fastly script ID in initial page"
Token extraction failed400"Could not extract token from challenge script"
No challenges returned400"No challenges received from post-back"
Unknown challenge type400"Unsupported challenge type: xyz"
Server rejected solutions400"Solution post-back rejected by server (status: error)"
No cookies after solving400"No _fs_ch cookies received after solving challenges"
Web Akamai

Web Akamai Solver API

Generate sensor data for Akamai-protected web applications.

Note: Documentation under construction. Will be available shortly.

注意:文档正在建设中,即将发布。