Metadata-Version: 2.5
Name: relyfinancials-sdk
Version: 0.1.2
Summary: Server-side Python SDK for Rely Identity, Organization, Billing, Wallet, Transactions, User, Inventory and POS APIs.
Project-URL: Documentation, https://github.com/killerbestshoot/rely/tree/main/packages/rely-sdk-python
Project-URL: Source, https://github.com/killerbestshoot/rely
License-Expression: LicenseRef-Proprietary
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
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: Topic :: Internet :: WWW/HTTP
Requires-Python: >=3.10
Requires-Dist: httpx<1,>=0.27
Description-Content-Type: text/markdown

# Rely Financials Python SDK

Server-side Python client for Rely Identity, organizations, branches and members, billing, wallet, transactions, inventory, and POS APIs. This package is released independently from the JavaScript SDK.

## Install

```bash
pip install relyfinancials-sdk
```

Python 3.10 or newer is required.

For local development from this monorepo, install the package in editable mode:

```bash
python -m pip install -e ./packages/rely-sdk-python
```

## Synchronous usage

```python
from rely_sdk import Rely, RelyAPIError

with Rely(client_id="YOUR_CLIENT_ID", client_secret="YOUR_CLIENT_SECRET") as rely:
    try:
        checkout = rely.checkout.create({
            "amount": "25.00",  # decimal string, with up to two decimal places
            "currency": "USD",
            "destination_wallet_id": "wallet-id",
            "success_url": "https://merchant.example/paid",
            "cancel_url": "https://merchant.example/cancelled",
            "webhook_url": "https://merchant.example/webhooks/rely",
            "order_id": "order-123",
        })
        print(checkout)
    except RelyAPIError as exc:
        print(exc.status, exc.code, exc.request_id, str(exc))

    # For an open session:
    rely.checkout.cancel(checkout["token"])

    # For a paid session instead:
    refund = rely.checkout.refund(checkout["token"], {
        "amount": "25.00",
        "idempotency_key": "order-123-refund-1",
        "reason": "Order returned",
    })
```

## Asynchronous usage

```python
from rely_sdk import AsyncRely

async with AsyncRely(client_id="YOUR_CLIENT_ID", client_secret="YOUR_CLIENT_SECRET") as rely:
    checkout = await rely.checkout.create({
        "amount": "25.00",
        "currency": "USD",
        "destination_wallet_id": "wallet-id",
        "success_url": "https://merchant.example/paid",
        "cancel_url": "https://merchant.example/cancelled",
        "webhook_url": "https://merchant.example/webhooks/rely",
    })
```

`AsyncRely` uses HTTPX's asynchronous client. Every network operation returns an awaitable.

## User and organization APIs

User and organization bearer tokens are passed explicitly to each method. Organization calls also take the organization ID first.

```python
with Rely() as rely:
    organizations = rely.organizations.list(access_token)
    branches = rely.branches.list(organization_id, access_token)

    payment_id = "payment-id"  # payment_id returned by payment_links.create(...)

    # For an unpaid link:
    rely.payment_links.cancel(organization_id, access_token, payment_id)

    # For a paid link instead:
    refunds = rely.payment_links.list_refunds(organization_id, access_token, payment_id)
    refund = rely.payment_links.refund(organization_id, access_token, payment_id, {
        "amount": "12.50",
        "idempotency_key": "invoice-42-refund-1",
    })

    # Named API domains retain the HTTP verb and route from the Rely API.
    products = rely.inventory.list_products(
        organization_id,
        access_token,
        query={"page": 1, "page_size": 25},
    )
    sale = rely.pos.create_sale(
        organization_id,
        access_token,
        body={"items": [{"variant_id": "variant-id", "quantity": 1}]},
    )
```

The grouped namespaces include `extensions`, `billing`, `wallet`, `transactions`, `user`, `inventory`, and `pos`. For registry-backed methods, pass path values as keyword arguments, and pass query or JSON data as `query=` or `body=`. For example:

```python
payment = rely.billing.payments.get_payment(access_token, payment_id="payment-id")
history = rely.wallet.get_history(access_token, query={"page": 1})
public_link = rely.billing.public.get_payment_link(token="public-token")

# The same Basic-authenticated merchant credentials configure `Rely`.
rely.billing.public.cancel_checkout_session(token="checkout-token")
refund = rely.billing.public.refund_checkout_session(
    token="checkout-token",
    body={"amount": "12.50", "idempotency_key": "order-123-refund-1"},
)

# POS sale refunds and payment-link cancellation use named organization routes.
sale_refund = rely.pos.refund_sale(
    organization_id,
    access_token,
    sale_id="sale-id",
    body={"amount": "12.50", "idempotency_key": "sale-refund-1"},
)
rely.pos.cancel_sale_payment_link(organization_id, access_token, sale_id="sale-id")
rely.billing.organization.cancel_pos_payment_link(
    organization_id, access_token, payment_id="pos-payment-id",
)
pos_link_refund = rely.billing.organization.refund_pos_payment_link(
    organization_id,
    access_token,
    payment_id="pos-payment-id",
    body={"amount": "12.50", "idempotency_key": "pos-refund-1"},
)
```

For a market POS scanner, send the decoded barcode as the `code` query value. The API resolves either a POS product or an inventory variant and returns the server-side price and stock details.

```python
item = rely.pos.lookup_catalog(
    organization_id,
    access_token,
    query={"code": scanned_code, "branch_id": branch_id},
)
```

JSON payloads use the API's snake_case field names. Call signatures for specialized helpers such as checkout, organizations, branches, members, invitations, and SDK tokens are exposed directly on those clients.

## Webhooks

Verify the signature against the exact raw request body before parsing or acting on an event. Do not parse and re-serialize the body before signature verification.

```python
from rely_sdk import construct_webhook_event

event = construct_webhook_event(raw_body, signature, webhook_secret)
# Deduplicate on event["event_id"] before processing.
```

The standalone `verify_webhook_signature(...)` helper returns `True` for a valid HMAC-SHA256 signature. Invalid signatures and invalid JSON raise `RelyWebhookSignatureError`.

## Configuration

`Rely` and `AsyncRely` accept `client_id`, `client_secret`, optional `api_base_url` and `auth_base_url`, `timeout` in seconds, `max_retries`, and `retry_base` in seconds. A single custom `api_base_url` is used for both gateways unless `auth_base_url` is also supplied. By default `/v1/identity/*` is routed to `https://auth.relyfinancials.cloud`; other API paths use `https://api.relyfinancials.cloud`.

Only GET requests are retried automatically (network errors, 429, and selected 5xx responses). Mutation calls are not retried to avoid duplicate charges or resource creation.

You can inject an existing `httpx.Client` or `httpx.AsyncClient` using `http_client=`. The SDK closes clients it creates itself; injected clients remain owned by the caller.

## Publishing

Increase the version before each release from the repository root:

```bash
python3 packages/rely-sdk-python/scripts/bump_version.py --bump patch
```

Use `--bump minor` or `--bump major` when appropriate. The command updates both `pyproject.toml` and `rely_sdk.__version__`; use `--dry-run` to preview the next version. Commit the change, then tag the commit using the resulting version, for example:

```bash
git add .github/workflows/publish-python-sdk.yml packages/rely-sdk-python
git commit -m "chore: release Python SDK 0.1.2"
git tag rely-sdk-python-v0.1.2
git push origin HEAD --tags
```

The GitHub Actions workflow verifies that the tag matches the package version, then builds and publishes the package. For token-based publishing, create a PyPI API token scoped to `relyfinancials-sdk`, then save it as the `PYPI_API_TOKEN` secret in the GitHub `pypi` environment. The workflow reads it as a secret and never writes it to the repository.
