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

# Python SDK

> Install the Stophy Python SDK, authenticate, call an endpoint sync or async, page through results, and handle errors and retries.

## Install

```bash theme={null}
pip install stophy
```

It needs Python 3.9 or newer.

## Authenticate

`api_key` defaults to the `STOPHY_API_KEY` environment variable, so a bare `Stophy()` picks it up.

```python theme={null}
import os

from stophy import Stophy

stophy = Stophy(api_key=os.environ["STOPHY_API_KEY"])
```

Without a key, Google search, Google News, YouTube search, video details and transcripts, Reddit search and Google Maps search still work. Here is Google search:

```python theme={null}
from stophy import Stophy

result = Stophy().google.search(query="bun runtime")
print(result["data"]["results"])
```

Every other endpoint raises `StophyError` with code `unauthorized` and status `401` when called without a key.

## Make a call

```python theme={null}
import os

from stophy import Stophy

stophy = Stophy(api_key=os.environ["STOPHY_API_KEY"])

posts = stophy.reddit.search(query="bun runtime")
print(posts["data"]["results"], posts["creditsUsed"])

transcript = stophy.youtube.transcript(video_url="https://youtu.be/dQw4w9WgXcQ")
print(transcript["data"]["text"])

ads = stophy.meta.ads.search(query="running shoes")
print(ads["data"]["results"])
```

Responses are plain dictionaries shaped like the [API reference](/api-reference/introduction): `success`, `data`, `creditsUsed` and `requestId`. `data` is a single dict, and lists are in `data["results"]`.

Methods follow the endpoint id, with keyword arguments in snake\_case. Nested ids are nested attributes: `reddit.search` is `stophy.reddit.search(...)`, and `google.maps.search` is `stophy.google.maps.search(...)`. A JSON field named `from` is passed as `from_`.

To point at one thing, send its link or its id, never both: `video_url` or `video_id`, `place_url` or `place_id`, `user_url` or `username`. The type checker shows the pair.

## Async

`AsyncStophy` has the same methods. Await them.

```python theme={null}
import asyncio

from stophy import AsyncStophy


async def main() -> None:
    async with AsyncStophy() as stophy:
        result = await stophy.google.search(query="bun runtime")
        for item in result["data"]["results"]:
            print(item["title"])


asyncio.run(main())
```

## Paging

```python theme={null}
import os

from stophy import Stophy

stophy = Stophy(api_key=os.environ["STOPHY_API_KEY"])
cursor = None
while True:
    page = stophy.reddit.search(query="bun runtime", cursor=cursor)
    print(page["data"]["results"])
    cursor = page["data"].get("cursor")
    if not cursor:
        break
```

## Handle errors and retries

```python theme={null}
from stophy import Stophy, StophyError

stophy = Stophy()

try:
    stophy.reddit.search(query="bun runtime")
except StophyError as error:
    print(error.status, error.code, str(error))
    print(error.retryable, error.retry_after_seconds, error.request_id)
```

`StophyError` has `status`, `code`, `retryable`, `retry_after_seconds` and `request_id`. The message is `str(error)`. See [Errors](/api-reference/errors) for every code.

The SDK retries network errors and `429`/`5xx` responses on its own, honoring `Retry-After`, before it raises. Set `max_retries=0` to turn that off. `StophyError` only reaches your code after retries are exhausted.

## Options

```python theme={null}
import os

from stophy import Stophy

stophy = Stophy(
    api_key=os.environ["STOPHY_API_KEY"],
    timeout=20.0,
    max_retries=3,
    retry_initial_delay=0.5,
    headers={"x-app": "my-app"},
)
```

| Option | Default | What it does |
| - | - | - |
| `api_key` | `STOPHY_API_KEY` | Your API key. Leave it unset to use Google search only. |
| `base_url` | `STOPHY_BASE_URL` or `https://api.stophy.dev` | Where requests go |
| `timeout` | `30.0` | Timeout in seconds |
| `max_retries` | `2` | Retries for network errors and `429`/`5xx`. `0` turns them off. |
| `retry_initial_delay` | `0.5` | Base backoff delay in seconds. Each retry waits longer than the last. |
| `headers` | none | Extra headers on every request |
| `transport` | none | An `httpx` transport, for tests |

Use the client as a context manager, or call `close()` when you are done.

## Usage and logs

These need an API key.

```python theme={null}
import os

from stophy import Stophy

stophy = Stophy(api_key=os.environ["STOPHY_API_KEY"])

usage = stophy.usage()
print(usage["balanceMicros"], usage["creditsUsed"], usage["requestCount"])

logs = stophy.logs(days=7, page=0, endpoint="google.search")
for entry in logs["logs"]:
    print(entry["createdAt"], entry["endpoint"], entry["credits"])
```

`balanceMicros` is your balance in millionths of a dollar. One credit is `1500`, so divide by 1,500 to get credits.


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