> ## Documentation Index
> Fetch the complete documentation index at: https://developers.perkstar.co.uk/llms.txt
> Use this file to discover all available pages before exploring further.

# Python SDK

> Use the official Perkstar Python client with retries, cursor pagination, typed errors, and webhook verification.

The official synchronous SDK supports Python 3.9 and newer. It covers every
operation in the public v1 API and is suited to Odoo modules, POS middleware,
scheduled syncs, and backend services.

## Install

Install the verified release from PyPI:

```bash theme={null}
python -m pip install "perkstar==0.1.2"
```

The wheel has no compiled extensions, so the same file works on Linux, macOS,
and Windows.

<Note>
  Releases are built and tested in GitHub Actions, published with PyPI Trusted
  Publishing, and accompanied by digital attestations. No long-lived PyPI
  password or upload token is stored in the repository.
</Note>

## Create a client

```python theme={null}
import os

from perkstar import Perkstar

with Perkstar(
    api_key=os.environ["PERKSTAR_API_KEY"],
    user_agent="MyOdooConnector/1.0",
) as perkstar:
    context = perkstar.marketplace.ping()
    print(context["data"]["organization"]["name"])
```

Pass `oauth_access_token=` instead of `api_key=` when your integration uses
OAuth. Pass exactly one credential type.

## Post a POS transaction

```python theme={null}
result = perkstar.marketplace.accrue(
    {
        "identifier": {"external_ref": "odoo:4:partner:981"},
        "card_id": "card_123",
        "transaction": {
            "type": "STAMP",
            "delta": 1,
            "external_transaction_id": "odoo:4:pos_order:94721",
        },
    },
    idempotency_key="odoo:4:pos_order:94721:loyalty",
)

print(result["enrollment"]["balance"])
```

The SDK generates an idempotency key for a new POST and preserves it across
automatic retries. Supply your own stable key when a durable job may restart in
a different process.

## Pagination

```python theme={null}
for customer in perkstar.customers.list(limit=100):
    sync_customer(customer)
```

Requests are lazy and follow `next_cursor` until the API reports no more rows.
An empty or repeated cursor stops with an error instead of looping forever.

## Typed errors

```python theme={null}
from perkstar import PerkstarError, PerkstarRateLimitError

try:
    post_loyalty()
except PerkstarRateLimitError as error:
    schedule_retry(error.retry_after)
except PerkstarError as error:
    print(error.code, error.request_id)
```

Network failures, `408`, `429`, and retryable `5xx` responses are retried up to
three times by default. The client honours `Retry-After` and keeps the API error
code, HTTP status, request ID, and API version on the raised exception.

## Verify webhooks

```python theme={null}
from perkstar import verify_webhook_signature

event = verify_webhook_signature(
    raw_request_body,
    request.headers["X-Perkstar-Signature"],
    webhook_secret,
)
```

Pass the exact raw `str` or `bytes` body. The helper uses constant-time HMAC
comparison and rejects timestamps outside a five-minute replay window.

## Verify the hosted fallback

Partners operating in locked-down environments can use the matching
Perkstar-hosted release and checksum:

```bash theme={null}
curl --fail --remote-name \
  https://dashboard.perkstar.co.uk/developer-downloads/perkstar-0.1.2-py3-none-any.whl
curl --fail --remote-name \
  https://dashboard.perkstar.co.uk/developer-downloads/SHA256SUMS
sha256sum --check SHA256SUMS --ignore-missing
```

The [source distribution](https://dashboard.perkstar.co.uk/developer-downloads/perkstar-0.1.2.tar.gz)
is also available for inspection and local builds.


## Related topics

- [Perkstar developer platform](/index.md)
- [Quickstart](/quickstart.md)
- [Changelog](/changelog.md)
- [TypeScript SDK](/sdks/typescript.md)
- [Pagination](/fundamentals/pagination.md)
