Metadata-Version: 2.4
Name: vorlek
Version: 1.0.1
Summary: Python SDK for the Vorlek email-marketing aggregation API
Project-URL: Homepage, https://vorlek.dev
Project-URL: Documentation, https://vorlek.dev/docs/sdk-py
Project-URL: Source, https://github.com/vorlek/vorlek-sdk-py
Project-URL: Issues, https://github.com/vorlek/vorlek-sdk-py/issues
Author-email: Vorlek <support@vorlek.com>
License-Expression: LicenseRef-Proprietary
License-File: LICENSE
Keywords: agents,email,klaviyo,mailchimp,sendgrid,vorlek
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: OS Independent
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: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx<1.0,>=0.27
Requires-Dist: python-ulid<4.0,>=2.0
Requires-Dist: typing-extensions>=4.8
Provides-Extra: dev
Requires-Dist: mypy>=1.13; extra == 'dev'
Requires-Dist: openapi-python-client~=0.28.3; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.7; extra == 'dev'
Description-Content-Type: text/markdown

# Vorlek Python SDK

Python client for the Vorlek API. It exposes the Phase 2 tool surface with
automatic idempotency keys, normalized `{data, meta}` results, and typed
exceptions for API and network failures.

```bash
pip install vorlek
```

Requires Python 3.10 or newer.

## Quickstart (sync)

```python
import os

from vorlek import VorlekClient

with VorlekClient(api_key=os.environ["VORLEK_API_KEY"]) as client:
    result = client.contact.upsert(
        provider="sendgrid",
        email="jamie@example.com",
        first_name="Jamie",
        properties={"plan": "free"},
    )

print(result.data["contact_id"])
print(result.meta.request_id)
```

## Quickstart (async)

```python
import asyncio
import os

from vorlek import AsyncVorlekClient


async def main() -> None:
    async with AsyncVorlekClient(api_key=os.environ["VORLEK_API_KEY"]) as client:
        result = await client.connection.status(provider="sendgrid")
        print(result.data["status"])
        print(result.meta.request_id)


asyncio.run(main())
```

## Methods

All tool calls are keyword-only and return `VorlekResult[T]`, where
`result.data` is the normalized tool payload and `result.meta` includes the
request id, quota state, rate-limit state, and idempotency replay state when
present.

| Namespace | Method | Endpoint |
| --- | --- | --- |
| `client.contact` | `upsert(...)` | `POST /v1/tools/upsert_contact` |
| `client.connection` | `status(...)` | `POST /v1/tools/get_connection_status` |
| `client.send` | `transactional(...)` | `POST /v1/tools/send_transactional` |
| `client.campaign` | `stats(...)` | `POST /v1/tools/get_campaign_stats` |
| `client.campaign` | `list(...)` | `POST /v1/tools/list_campaigns` |
| `client.template` | `list(...)` | `POST /v1/tools/list_templates` |

Supported providers are `sendgrid`, `mailchimp`, and `klaviyo`. Argument
types are generated from the live OpenAPI schema and are also documented at
<https://vorlek.dev/openapi.json>.

## Error handling

Vorlek raises subclasses of `VorlekError`. Caller mistakes are grouped under
`VorlekClientError`, while more specific classes let applications handle common
cases directly.

```python
from vorlek import (
    VorlekClient,
    VorlekClientError,
    VorlekError,
    VorlekRateLimitedError,
    is_retryable_error,
)

client = VorlekClient(api_key="vk_live_...")

try:
    result = client.contact.upsert(provider="sendgrid", email="jamie@example.com")
except VorlekRateLimitedError as err:
    print(f"rate limited, retry after {err.retry_after} seconds")
except VorlekClientError as err:
    print(f"fix the request before retrying: {err.code} {err.message}")
except VorlekError as err:
    if is_retryable_error(err):
        print(f"retry with backoff: {err.code}")
    else:
        print(f"not retry-safe: {err.code}")
else:
    print(result.data)
finally:
    client.close()
```

Every error exposes `code`, `category`, `retry_safe`, `http_status`,
`request_id`, `provider`, `retry_after`, and `detail`.

## Idempotency

Every tool call sends an `Idempotency-Key` header. By default the SDK generates
a fresh ULID per request.

Pass `idempotency_key` to retry one logical operation with the same key:

```python
result = client.contact.upsert(
    provider="mailchimp",
    email="jamie@example.com",
    idempotency_key="01HV0011V0110011V011001100",
)
print(result.meta.idempotency.replay if result.meta.idempotency else False)
```

Calling the same key twice with the same request body is safe. Reusing the same
key with a different body raises `VorlekIdempotencyConflictError`.

## `from_` on transactional sends

Python reserves `from` as a keyword, so the SDK accepts `from_` and sends it to
the API as `from`.

```python
client.send.transactional(
    provider="sendgrid",
    to="jamie@example.com",
    from_="updates@example.com",
    subject="Welcome",
    text="Thanks for trying Vorlek.",
)
```

## Test mode

`vk_test_*` keys pass through the SDK today. Full test-mode behavior, including
provider-free deterministic tool responses, is planned for Phase 3.6 and will
be documented at <https://vorlek.dev/docs/test-mode> when it ships.

## Examples

The `examples/` directory contains small scripts that run from a virtual
environment:

```bash
export VORLEK_API_KEY=vk_live_...
python examples/upsert.py
python examples/send_transactional.py
python examples/cross_provider_round_trip.py
```

Each script exits successfully with a skip message when required environment
variables are missing.

## Cross-SDK parity

The TypeScript SDK is published as `@vorlek/sdk`. Both SDKs surface the same
`{data, meta}` success contract and the same six tool namespaces. Python v1
ships the full 18-class error hierarchy; the TypeScript retrofit is tracked at
<https://github.com/vorlek/vorlek-sdk-ts/issues/2>.

## Local development

```bash
python -m venv .venv
. .venv/bin/activate
pip install -e ".[dev]"

ruff check .
ruff format --check .
mypy src/vorlek
pytest -q
python scripts/generate_types.py && git diff --exit-code src/vorlek/_generated/
```
