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

# Python SDK

> Sync and async Python client for every OmniCommerce REST endpoint.

The Python SDK (`omnicommerce`) is generated from the same public OpenAPI spec as the [TypeScript SDK](/sdk/typescript). Every documented REST operation is a resource method. Responses are parsed JSON: objects are dicts, arrays are lists, and an empty body is `None`.

## Install

Install the SDK from PyPI:

```bash theme={null}
python3 -m pip install omnicommerce
```

Requires Python 3.10+.

```python theme={null}
import os
from omnicommerce import AsyncOmni, Omni
```

## Authenticate

Use an organization API key (`omni_sk_...`) as a bearer token. Do not send `organization_id` on API-key requests.

```python theme={null}
client = Omni(api_key=os.environ["OMNI_API_KEY"])
```

Omit `api_key` to read `OMNI_API_KEY`. Override the host with `base_url` or `environment` (`https://omnicommerce.sg` by default). `OmniEnvironment.LOCAL` is `http://localhost:3000`. See [Authentication](/authentication).

```python theme={null}
from omnicommerce import Omni, OmniEnvironment

client = Omni(
    api_key=os.environ["OMNI_API_KEY"],
    environment=OmniEnvironment.LOCAL,
    timeout_in_seconds=60,
    max_retries=2,
)
```

Use the client as a context manager so the HTTP connection closes. `AsyncOmni` is the async client and uses `async with`.

## Resource clients

Each call takes keyword arguments. Path, query, and JSON fields keep their wire names in snake\_case: `productId` is `product_id`, `minPrice` is `min_price`.

```python theme={null}
products = client.products.list(q="lamp")

job = client.products.create(
    product={
        "sku": "SKU-100",
        "title": "Sample product",
        "price": 29.9,
        "currency": "SGD",
        "images": ["https://cdn.example.com/product.jpg"],
    }
)
client.jobs.wait(job_id=job["jobId"])

publish = client.products.publish(product_id="prod_123", visibility="live")
client.jobs.wait(job_id=publish["jobId"])

delist = client.products.delist(
    product_id="prod_123",
    marketplaces=["shopee", "lazada"],
)
client.jobs.wait(job_id=delist["jobId"])
```

Per-request overrides:

```python theme={null}
from omnicommerce import RequestOptions

client.orders.get(
    order_id="ord_123",
    request_options=RequestOptions(timeout_in_seconds=15),
)
```

`client.with_raw_response.orders.get(...)` returns `data`, `status_code`, `headers`, and `url`.

```python theme={null}
async with AsyncOmni(api_key=os.environ["OMNI_API_KEY"]) as client:
    products = await client.products.list(q="lamp")
```

## Product inventory

Response keys keep their API casing even though method arguments use snake\_case. Read `page["items"]` and each row's `stockQuantity`, `hasVariants`, and `variantCount`.

```python theme={null}
page = client.products.list(q="lamp")
for product in page["items"]:
    quantity = product.get("stockQuantity")
    print(product["id"], "Unknown stock" if quantity is None else quantity)
```

`stockQuantity` is catalog stock, matching the Products page. Parent rows already aggregate their variants; virtual bundles already account for component stock and any manual cap. Preserve null or missing values as unknown. Do not read `inventoryQuantity`, `inventory.quantity`, or `stock_quantity`, and do not sum a missing `variants` array. See [Product inventory](/sdk/typescript#product-inventory) for quantity semantics.

## Coverage

| Client | Examples |
| - | - |
| `client.products` | `list`, `create`, `get`, `update`, `delete`, `publish`, `delist`, `bulk_import`, `enrich` |
| `client.orders` | `list`, `create`, `get`, `update` |
| `client.promotions` | `list`, `create`, `get`, `update`, `delete`, `sync` |
| `client.price_books` | `list`, `create`, `get`, `update`, `delete`, `preview` |
| `client.aop` | `create`, `execute`, `get_config`, `update_config`, `retry` |
| `client.jobs` | `get`, `cancel`, `wait` |
| `client.webhooks` | `list`, `create` |
| `client.checkout_sessions` | `create`, `get`, `update`, `complete`, `cancel` |
| `client.ucp` | `checkout_sessions`, `orders` |
| `client.oauth` | `token`, `revoke` |

Looks, returns, settlements, marketplaces, search, evaluate, monitor, sync, Zalora, and the remaining documented tags follow the same pattern.

## Errors

Non-2xx responses raise `OmniError` subclasses. See [SDK errors](/sdk/errors).

GET, HEAD, OPTIONS, PUT, and DELETE retry on 5xx and network failures. 408 and 429 retry for every method. POST and PATCH are not retried on 5xx.

## Webhooks

```python theme={null}
from omnicommerce import construct_event

event = construct_event(raw_body, request.headers, os.environ["OMNI_WEBHOOK_SECRET"])
```

HMAC-SHA256 over `{timestamp}.{raw_body}` compared to `X-Omni-Signature`. See [Webhooks](/webhooks/overview).

## Regenerate

From this repository:

```bash theme={null}
yarn sdk:generate
```


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