Cru Trading API for Python
The Python SDK for the Cru Trading API, Cru World Wine's
partner REST API. Read Cru's live bid and offer books for every wine, manage your own bids and
offers, see your portfolio, purchases and sales, and trade: buy an offer or sell into a bid. It has
a synchronous client, Cru, and an asyncio one, AsyncCru, with typed models for every answer,
automatic retries and OAuth token refresh, and nothing to install beyond
httpx.
Installation
pip install cruworldwine
Python 3.9 or later.
Connecting
With a partner credential, whose writes run at once:
from cruworldwine import Cru
with Cru(client_key='cru_live_...', client_secret='...', market='uk') as cru:
client = cru.ping().client
print(client.organisation, client.market, client.currency, client.scopes)
Or with asyncio, here as a connected app acting for a customer, whose writes wait for the customer to confirm them:
import asyncio
from cruworldwine import AsyncCru
async def main() -> None:
async with AsyncCru(access_token='...', refresh_token='...', oauth_client_id='...') as cru:
page = await cru.bids.list(status=['live'])
async for bid in page:
print(bid.code, bid.price, bid.quantity)
asyncio.run(main())
Cru() alone reads CRU_CLIENT_KEY and CRU_CLIENT_SECRET (or CRU_ACCESS_TOKEN),
CRU_MARKET and CRU_ENVIRONMENT from the environment. Authentication
covers both ways in.
Sandbox
To build and test where no real money or wine changes hands, use the sandbox, with credentials
issued for it: environment='sandbox' (or CRU_ENVIRONMENT=sandbox) calls
https://{market}.crusandbox.com/api/v1 in place of https://{market}.cruworldwine.com/api/v1.
cru = Cru(client_key='...', client_secret='...', environment='sandbox', market='hk')
print(cru.market_info.currency) # HKD
MARKETS and lookup_market() list each market's name, currency, symbol and URLs;
Configuration has the details.
Typed models
Every endpoint is a typed method, and every answer a typed model with an attribute per API field
and the API's descriptions as docstrings, so an editor completes and checks them. Fields this
version does not know are kept in .raw.
for wine in cru.portfolio.list(is_listed=True).auto_paging_iter(): # PortfolioWine
for line in wine.portfolio: # PortfolioLine
print(wine.wine_name, line.quantity, line.pricing.listing_price, line.pricing.net_proceeds)
Import any model from cruworldwine.models.
Documentation
- Authentication: partner credentials, connected apps and OAuth refresh, the environment.
- Configuration: constructor and per-call options, the sandbox and the
markets,
with_options(), timeouts, retries, logging,app_info. - Async:
AsyncCru, async paging and concurrency. - Pagination: pages, and walking every item.
- Writes and confirmations: idempotency references, staged writes and confirming them.
- Errors: the error classes, what they hold, and request ids.
- Compatibility: tolerant models, values that may grow, and the versioning policy.
- Architecture: how the SDK is built, the life of a request, and the code generation.
- The API itself: developers.cruworldwine.com.
Examples
examples/ has scripts to run with credentials in the environment: portfolio.py
prints your portfolio, market.py the bids and offers on a wine, place_bid.py places a bid and,
as a connected app, confirms it, and async_market.py asks for several wines at once with
AsyncCru.
Versioning and support
The SDK follows semantic versioning. While it is 0.x, a minor release may change the public API, and every such change is in the changelog; patch releases never do. It supports Python 3.9 to 3.15 on Linux, macOS and Windows, and only the latest minor release gets fixes. Compatibility has the whole policy.
Every method
Generated from the spec; each method's docstring has the full description. AsyncCru has the
same methods: await them, and a Page is an AsyncPage.
| Method | Endpoint | Returns |
|---|---|---|
cru.ping() |
GET /ping |
Ping |
cru.portfolio.list(...) |
GET /portfolio |
Page[PortfolioWine] |
cru.offers.list(...) |
GET /offers |
Page[PortfolioWine] |
cru.offers.create(...) |
POST /offers |
Write[OfferResult] |
cru.offers.get(code) |
GET /offers/{code} |
PortfolioWine |
cru.offers.update(code, ...) |
PATCH /offers/{code} |
Write[OfferResult] |
cru.offers.remove(code, ...) |
DELETE /offers/{code} |
Write[OfferRemoveResult] |
cru.bids.list(...) |
GET /bids |
Page[OwnBid] |
cru.bids.place(...) |
POST /bids |
Write[BidResult] |
cru.bids.get(code) |
GET /bids/{code} |
OwnBid |
cru.bids.update(code, ...) |
PATCH /bids/{code} |
Write[BidResult] |
cru.bids.cancel(code, ...) |
DELETE /bids/{code} |
Write[BidResult] |
cru.bids.renew(code, ...) |
POST /bids/{code}/renew |
Write[BidResult] |
cru.market.list(...) |
GET /market |
Page[MarketWine] |
cru.market.get_wine(lwin18, ...) |
GET /market/wines/{lwin18} |
MarketWine |
cru.market.list_bids(...) |
GET /market/bids |
Page[MarketWine] |
cru.market.get_bid(code) |
GET /market/bids/{code} |
MarketBidDetail |
cru.market.get_wine_bids(lwin18, ...) |
GET /market/wines/{lwin18}/bids |
MarketWine |
cru.market.list_offers(...) |
GET /market/offers |
Page[MarketWine] |
cru.market.get_offer(code) |
GET /market/offers/{code} |
MarketOfferDetail |
cru.market.get_wine_offers(lwin18, ...) |
GET /market/wines/{lwin18}/offers |
MarketWine |
cru.market.buy_offer(code, ...) |
POST /market/offers/{code}/buy |
Write[BuyResult] |
cru.market.sell_to_bid(code, ...) |
POST /market/bids/{code}/sell |
Write[SellResult] |
cru.wines.search(...) |
GET /wines |
Page[Wine] |
cru.wines.get(lwin18) |
GET /wines/{lwin18} |
WineDetail |
cru.trades.list_purchases(...) |
GET /trades/purchases |
Page[Purchase] |
cru.trades.list_sales(...) |
GET /trades/sales |
Page[Sale] |
cru.warehouses.list() |
GET /warehouses |
list[Warehouse] |
cru.warehouses.get(code) |
GET /warehouses/{code} |
Warehouse |
cru.inbond_warehouses.list() |
GET /warehouses/inbond |
list[InbondWarehouse] |
cru.inbond_warehouses.suggest(...) |
POST /warehouses/inbond |
Write[InbondWarehouseResult] |
cru.inbond_warehouses.get(id) |
GET /warehouses/inbond/{id} |
InbondWarehouse |
cru.inbond_addresses.list() |
GET /addresses/inbond |
list[InbondAddress] |
cru.inbond_addresses.add(...) |
POST /addresses/inbond |
Write[InbondAddressResult] |
cru.inbond_addresses.remove(id, ...) |
DELETE /addresses/inbond/{id} |
Write[InbondAddressResult] |
cru.confirmations.get(code) |
GET /confirmations/{code} |
Confirmation |
cru.confirmations.confirm(code) |
POST /confirmations/{code} |
Write[Any] |
cru.confirmations.cancel(code) |
DELETE /confirmations/{code} |
None |
cru.photos.get(id) |
GET /photos/{id} |
bytes |
Contributing, security and licence
CONTRIBUTING.md explains the layout, the Makefile and how releases are cut. Report a vulnerability privately, as SECURITY.md explains, never in a public issue. Apache License 2.0; see LICENSE.
Metadata
Release files for cruworldwine 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| cruworldwine-0.2.0.tar.gz | 97.5 kB | With provenance | Details for cruworldwine-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| cruworldwine-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for cruworldwine-0.2.0-py3-none-any.whl |
Total release size: 186.9 kB
Release files / cruworldwine-0.2.0.tar.gz
| Download URL | cruworldwine-0.2.0.tar.gz |
|---|---|
| Size | 97.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
290a687a0461d2208d74a9ef19f2662f005561b17fb1dc8b61c96a70d7e2dbc8
|
|
BLAKE2b-256 checksum How to use checksums |
27f6b82e503a10cb77fb8bc72790069a383e9e0cbfbb87c4f52c4ca4c659ddb9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logRelease files / cruworldwine-0.2.0-py3-none-any.whl
| Download URL | cruworldwine-0.2.0-py3-none-any.whl |
|---|---|
| Size | 89.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8622e8c28ae4a926ba53db3224bce8fa363d31591466aaa2793964448f76bde5
|
|
BLAKE2b-256 checksum How to use checksums |
208b1e15d1d21bc219ed3ce0ecab5fcb6d580be46a0fcaad9415f110e9ca46a5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logSecurity for cruworldwine 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for cruworldwine-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.