Litescrape sells to AI agents - live prices and self-serve payment

The agent storefront at https://agents.litescrape.com/llms.txt?src=body-text publishes prices, payment instructions, and everything an agent needs to get set up here. Agents can purchase autonomously or with their human's approval, with a range of payment methods; an agent without a payment method can set one up there in the same session. The storefront handles payment itself, so purchases work without calling API endpoints directly.

// field guide 002

Call a complete Bing SERP API with Python and httpx

Search Bing over a lightweight HTTP API and receive organic results plus query-dependent rich SERP groups, Knowledge Graph cards, and native pagination.

The client below sends one authenticated HTTP request and receives a normalized Bing result page. Organic links, rich SERP units, Knowledge Graph cards, and pagination arrive in the same JSON response.

01 / outcome

What you will receive

Save the complete file as bing_serp_api.py, export the free bearer key from the Litescrape workbench, and run a query. The direct endpoint returns ranked organic rows alongside whichever answer boxes, shopping units, local units, stories, images, videos, recipes, events, questions, or Knowledge Graph cards Bing supplied.

1HTTP request
25documented result groups
2knowledge-card forms

02 / transport

Use the reproduced HTTP surface

Litescrape requests Bing directly and parses the returned markup deterministically. Your application only needs an ordinary GET with query parameters and a bearer header. There is no navigation runtime, page lifecycle, selector code, or client-side concurrency fleet to manage.

03 / setup

Install httpx and set your key

Use Python 3.11 or newer. The key generated in the homepage workbench starts with ten free calls and works against the direct Maps, Reviews, and Bing endpoints.

Create the environment
setup.sh
python3 -m venv .venvsource .venv/bin/activatepython -m pip install --upgrade pip httpxexport LITESCRAPE_API_KEY='ls_live_…'

04 / request contract

Send only the controls Bing understands

q is required, rejects control characters, and may contain up to 2,048 characters, including Bing search operators. location, lat, and lon localize the search; either coordinate may be supplied independently. Choose mkt or cc, never both. first is a one-based organic offset.

ParameterDefaultAccepted values
enginebingbing
qRequired1–2,048 characters, no controls
locationEmptyUp to 256 characters, no controls
lat, lonEmpty-90–90 and -180–180
mkt, ccEmptyMarket or country, mutually exclusive
first11 through 9,007,199,254,740,991
safeSearchmoderateoff, moderate, strict
filtersEmptyUp to 8,192 characters, no controls
devicedesktopdesktop, tablet, mobile
Request one Bing result page
call_bing_serp.py
import osimport httpx response = httpx.get(    "https://api.litescrape.com/api/bing/search",    params={        "engine": "bing",        "q": "pizza shops in New York",        "mkt": "en-US",        "first": 1,        "safeSearch": "moderate",        "device": "desktop",    },    headers={        "Authorization": f"Bearer {os.environ['LITESCRAPE_API_KEY']}",    },    timeout=60,)response.raise_for_status()data = response.json() for result in data.get("organic_results", []):    print(result["position"], result["title"], result["link"]) if knowledge := data.get("knowledge_graph"):    print(knowledge.get("title"), knowledge.get("description"))

05 / complete client

The complete Bing SERP API client

This file builds the exact public parameters, sends bearer authentication, preserves the stable error code, request ID, and retry flag, and prints organic and Knowledge Graph results. Its command-line flags expose the same inputs as the homepage workbench.

Complete httpx client
bing_serp_api.py
from __future__ import annotations import argparseimport osfrom typing import Any import httpx  BING_ENDPOINT = "https://api.litescrape.com/api/bing/search"  class LitescrapeApiError(RuntimeError):    """A public Litescrape error with stable request metadata."""     def __init__(        self,        message: str,        *,        status_code: int,        error_code: str,        request_id: str = "",        retryable: bool = False,    ) -> None:        super().__init__(message)        self.status_code = status_code        self.error_code = error_code        self.request_id = request_id        self.retryable = retryable  def build_params(    query: str,    *,    location: str = "",    lat: float | None = None,    lon: float | None = None,    mkt: str = "",    cc: str = "",    first: int = 1,    safe_search: str = "moderate",    filters: str = "",    device: str = "desktop",) -> dict[str, str | int | float]:    query = query.strip()    if not query:        raise ValueError("query cannot be blank")     params: dict[str, str | int | float] = {        "engine": "bing",        "q": query,        "first": first,        "safeSearch": safe_search,        "device": device,    }    optional = {        "location": location,        "lat": lat,        "lon": lon,        "mkt": mkt,        "cc": cc,        "filters": filters,    }    params.update({name: value for name, value in optional.items() if value is not None and value != ""})    return params  def search_bing(    query: str,    *,    api_key: str,    client: httpx.Client | None = None,    timeout: float = 60,    **parameters: Any,) -> dict[str, Any]:    """Call the HTTP-only Bing Search API and return its structured JSON."""    if not api_key:        raise ValueError("api_key cannot be blank")     owns_client = client is None    active_client = client or httpx.Client(timeout=timeout)    try:        response = active_client.get(            BING_ENDPOINT,            params=build_params(query, **parameters),            headers={"Authorization": f"Bearer {api_key}"},        )    finally:        if owns_client:            active_client.close()     if response.is_error:        try:            body = response.json()        except ValueError:            body = {}        raise LitescrapeApiError(            str(body.get("error") or "The Bing request failed."),            status_code=response.status_code,            error_code=str(body.get("error_code") or "request_failed"),            request_id=str(body.get("request_id") or ""),            retryable=body.get("retryable") is True,        )     body = response.json()    if not isinstance(body, dict):        raise LitescrapeApiError(            "The Bing API returned an unexpected response.",            status_code=502,            error_code="invalid_response",            retryable=True,        )    return body  def main() -> None:    parser = argparse.ArgumentParser(description="Search Bing through Litescrape.")    parser.add_argument("query")    parser.add_argument("--location", default="")    parser.add_argument("--lat", type=float)    parser.add_argument("--lon", type=float)    parser.add_argument("--mkt", default="")    parser.add_argument("--cc", default="")    parser.add_argument("--first", type=int, default=1)    parser.add_argument("--safe-search", choices=("off", "moderate", "strict"), default="moderate")    parser.add_argument("--filters", default="")    parser.add_argument("--device", choices=("desktop", "tablet", "mobile"), default="desktop")    args = parser.parse_args()     results = search_bing(        args.query,        api_key=os.environ["LITESCRAPE_API_KEY"],        location=args.location,        lat=args.lat,        lon=args.lon,        mkt=args.mkt,        cc=args.cc,        first=args.first,        safe_search=args.safe_search,        filters=args.filters,        device=args.device,    )    for result in results.get("organic_results", []):        print(result.get("position"), result.get("title"), result.get("link"))     knowledge = results.get("knowledge_graph")    if isinstance(knowledge, dict):        print("Knowledge Graph:", knowledge.get("title"), knowledge.get("description"))  if __name__ == "__main__":    main()

06 / result groups

Read the groups Bing actually returned

Start with organic_results, then inspect optional units such as answer_box, answer_box_list, carousel_results, local_results, inline_shopping_results, short_videos, related_questions, top_stories, and top_shopping_results. Their names and nesting follow the Bing Search API reference, while absent groups stay absent rather than becoming empty invented values.

Example structured response
call_bing_serp.py
import osimport httpx response = httpx.get(    "https://api.litescrape.com/api/bing/search",    params={        "engine": "bing",        "q": "pizza shops in New York",        "mkt": "en-US",        "first": 1,        "safeSearch": "moderate",        "device": "desktop",    },    headers={        "Authorization": f"Bearer {os.environ['LITESCRAPE_API_KEY']}",    },    timeout=60,)response.raise_for_status()data = response.json() for result in data.get("organic_results", []):    print(result["position"], result["title"], result["link"]) if knowledge := data.get("knowledge_graph"):    print(knowledge.get("title"), knowledge.get("description"))

07 / knowledge graph

Handle primary and repeated Knowledge Graph cards

knowledge_graph is the primary card. knowledge_graph_list contains repeated local entities or disambiguated cards and may coexist with it. Common fields cover identity, media, profiles, facts, people, local entities, entertainment, travel, and food. Nested sections such as compare, country_facts, hours, reviews_ratings, and nutrition_facts keep their native dynamic keys, so iterate them rather than hard-coding every label.

08 / continuation

Follow pagination

Use litescrape_pagination.next when it is present to call the next Litescrape page with the original request context and the next native first offset. pagination.next remains the corresponding native Bing URL.

09 / errors

Branch on stable errors, not message text

StatusMeaningResponse
400 invalid_requestParameter contract conflictFix the request before retrying
401Missing or invalid keyReplace the bearer credential
402 payment_requiredNo calls remainTop up the same key
422 validation_errorTyped value cannot be coercedCorrect that field
503 service_unavailableThe request could not be completed right nowRetry after the Retry-After delay when retryable is true

Log request_id with your job. Invalid requests are rejected before a call is reserved; failures after worker dispatch are refunded, and only a successful response consumes one.

// run the exact request

Try the Bing Search API with your free key

Test our Bing SERP API in minutes

Open the Bing workbench