Metadata-Version: 2.4
Name: bytekit-sdk
Version: 0.3.0
Summary: Official Python SDK for the ByteKit API
Project-URL: Homepage, https://bytekit.com
Project-URL: Repository, https://github.com/Hunt-Labs-Inc/ByteKit
Project-URL: Documentation, https://bytekit.com/docs
License-Expression: MIT
Keywords: api,bytekit,crawler,llm,markdown,scraping,screenshots,sdk,web-scraping
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: attrs>=23.1.0
Requires-Dist: httpx>=0.24.0
Requires-Dist: python-dateutil>=2.8.0
Description-Content-Type: text/markdown

# bytekit-sdk

Official Python SDK for the [ByteKit API](https://bytekit.com).

The PyPI **distribution** is `bytekit-sdk`; the **import** name is `bytekit`.

Generated from the OpenAPI spec using [openapi-python-client](https://github.com/openapi-generators/openapi-python-client), filtered to the stable v0.1 operations.

## Installation

```bash
pip install bytekit-sdk
```

## Quick start

```python
from bytekit import AuthenticatedClient
from bytekit.api.scrape import create_scrape
from bytekit.errors import UnexpectedStatus
from bytekit.models.scrape_request import ScrapeRequest

# base_url defaults to https://api.bytekit.com, so only the token is required.
client = AuthenticatedClient(token="sk_live_your_api_key_here")

body = ScrapeRequest(url="https://example.com")

try:
    response = create_scrape.sync(client=client, body=body)
    # response.formats.markdown is str | Unset — only present when "markdown" was requested
    print(response.formats.markdown)
except UnexpectedStatus as err:
    # Errors now raise loudly by default instead of returning None.
    print(f"request failed with status {err.status_code}: {err.code} {err.message}")
```

### Defaults

The client ships with production-ready defaults so `AuthenticatedClient(token=...)` works out of the box:

| Setting                      | Default                         | Notes                                                                                                                                                           |
| ---------------------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `base_url`                   | `https://api.bytekit.com`       | Pass `base_url=` to target staging or a proxy.                                                                                                                  |
| `timeout`                    | `120s` (`httpx.Timeout(120.0)`) | Finite by default — requests no longer hang indefinitely. Pass `timeout=` to override.                                                                          |
| `raise_on_unexpected_status` | `True`                          | Undocumented statuses raise `errors.UnexpectedStatus` instead of silently returning `None`. Pass `raise_on_unexpected_status=False` to restore the old opt-out. |

Explicit constructor arguments always win over these defaults (explicit arg > default).

## Async usage

```python
import asyncio
from bytekit import AuthenticatedClient
from bytekit.api.screenshots import create_screenshot
from bytekit.models.screenshot_request import ScreenshotRequest

async def main():
    client = AuthenticatedClient(token="sk_live_your_api_key_here")
    body = ScreenshotRequest(url="https://example.com")
    response = await create_screenshot.asyncio(client=client, body=body)
    print(response)

asyncio.run(main())
```

## Available operations

| Module            | Method                                                                                                        | Description                                |
| ----------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
| `api.scrape`      | `create_scrape`, `get_scrape`                                                                                 | Web content extraction                     |
| `api.screenshots` | `create_screenshot`, `get_screenshot`                                                                         | Page screenshots                           |
| `api.bulk`        | `create_bulk`, `get_bulk`, `delete_bulk`, `list_bulk_screenshots`                                             | Bulk screenshot jobs                       |
| `api.scrape_bulk` | `create_scrape_bulk`, `get_scrape_bulk`                                                                       | Bulk scrape jobs                           |
| `api.fetch`       | `get_fetch`, `post_fetch`                                                                                     | Raw HTTP fetch                             |
| `api.fetch_bulk`  | `create_fetch_bulk`, `get_fetch_bulk`                                                                         | Bulk fetch jobs                            |
| `api.monitors`    | `create_monitor`, `list_monitors`, `get_monitor`, `update_monitor`, `delete_monitor`, `list_monitor_captures` | Page-change monitors (screenshot + scrape) |
| `api.sitemap`     | `create_sitemap`, `get_sitemap`                                                                               | Sitemap crawl                              |
| `api.search`      | `create_search` (or the `AuthenticatedClient.search(...)` convenience method)                                 | Web search                                 |
| `api.usage`       | `get_usage`, `get_usage_daily`, `get_usage_by_endpoint`                                                       | Account usage & billing                    |
| `api.webhooks`    | `list_webhook_deliveries`, `retry_webhook_delivery`                                                           | Webhook delivery log & retry               |
| `api.account`     | `get_account`                                                                                                 | Account details                            |

## Regenerating

To regenerate the client after API changes:

```bash
pnpm --filter @bytekit/sdk-python generate
```

This runs `scripts/filter-spec.ts` to produce `filtered-openapi.yaml` (filtered to v0.1 operations), runs `scripts/prune-stale-api.py` to delete any `src/bytekit/api/<tag>/` directory the filtered spec no longer produces (`generate --overwrite` itself already rebuilds `api/` from scratch on every run, so this step is defense-in-depth for a standalone run of the prune script or a future generator version — the path that actually needs the guard is `pnpm generate:docs`, which enumerates `api/` on disk independent of `generate` and can otherwise resurrect a tag whose tracked files were `git rm`-ed but whose untracked `__pycache__/` survives; see `scripts/prune-stale-api.py`'s module docstring and `has_operations()` in `scripts/generate-docs.py`), invokes `openapi-python-client generate` to update `src/bytekit/`, then runs `scripts/inject-handwritten.py` to re-append hand-written fragments (e.g. the `AuthenticatedClient.search()` convenience method) from `scripts/hand_written/` and re-patch the generated `client.py`/`errors.py` with the runtime defaults and error enrichment described above — because `--overwrite` overwrites every file it emits, both the hand-written code and these patches are wiped on every regen and must be re-applied afterward.

## Development

```bash
# Run tests
cd packages/sdk-python
python3 -m pytest tests/ -v
```

## Publishing

PyPI publish is handled in [#2226](https://github.com/Hunt-Labs-Inc/ByteKit/issues/2226) —
`.woodpecker/publish.yaml`'s `publish-pypi` step, version-gated the same way as the npm
siblings (publishes only when the local `pyproject.toml` version differs from what's live on
PyPI).

**`bytekit-sdk` has never been published.** Before the commit that arms
`packages/sdk-python/pyproject.toml` in `publish.yaml`'s workflow-level `when.path.include` is
promoted from `staging` to `main`, an operator MUST publish `0.3.0` to PyPI manually and under
supervision. Reason: bytekit-sdk 404s on PyPI today, so the automatic version-compare gate's
`|| echo "0.0.0"` fallback always fires — the first time that arming reaches `main`, it would
trigger a real, irreversible first `twine upload` with no manual confirmation step in between.
Once the manual first release exists, PUBLISHED == CURRENT and every later automatic run at an
unchanged version is a no-op, same as the npm packages. See the comment at the armed
`when.path.include` entry in `.woodpecker/publish.yaml` for the mechanism.
