Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.11.0"
".": "0.11.1"
}
8 changes: 4 additions & 4 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 21
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/azure/partnermax-10329cc51f6b17a164e474568823469dcf6dda933ed001cf5da70440a7e55dd7.yml
openapi_spec_hash: 1c0790919f1143b6ec46ba0c811a86f4
config_hash: 18c6c7df17bad3320b9f2c126947f00a
configured_endpoints: 20
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/azure/partnermax-fa55dc70ae5286c71a0faea047e23dfbb93be0bbfa3d7a0776d06c12a376444a.yml
openapi_spec_hash: 841e984b131bfb9b83d26fdd9dbd5303
config_hash: 410d10ad3652f4fdf97d2bd563de0d64
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# Changelog

## 0.11.1 (2026-06-27)

Full Changelog: [v0.11.0...v0.11.1](https://github.com/DealerMax-app/partnermax-python/compare/v0.11.0...v0.11.1)

### Bug Fixes

* regenerate SDK for PartnerMAX contract 1.5.3 ([ed19bab](https://github.com/DealerMax-app/partnermax-python/commit/ed19bab778dbe4c5dc148b9d1c4ee22ffde38308))
* regenerate SDK with active dealer methods ([62bdc98](https://github.com/DealerMax-app/partnermax-python/commit/62bdc98e17d9222d23199332da41a40cc78f4dfc))


### Chores

* update SDK settings ([957f874](https://github.com/DealerMax-app/partnermax-python/commit/957f874069a07618175ba519778cf850071b6536))
* update SDK settings ([efc6309](https://github.com/DealerMax-app/partnermax-python/commit/efc630962361b39f78f40008dc883bb7c9a33b98))

## 0.11.0 (2026-06-26)

Full Changelog: [v0.10.1...v0.11.0](https://github.com/DealerMax-app/partnermax-python/compare/v0.10.1...v0.11.0)
Expand Down
122 changes: 88 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,11 @@ client = Partnermax(
environment="sandbox",
)

dealer_detail = client.dealers.create(
address="xx",
business_name="Rossi Automobili S.R.L.",
city="xx",
contact_email="info@rossi-auto.it",
contact_phone="xxxxx",
postal_code="20121",
primary_domain="rossi-auto.it",
province_code="MI",
vat_number="IT01234567890",
page = client.dealers.list(
limit=10,
status="active",
)
print(dealer_detail.dealer_id)
print(page.data)
```

While you can provide an `api_key` keyword argument,
Expand All @@ -70,18 +63,11 @@ client = AsyncPartnermax(


async def main() -> None:
dealer_detail = await client.dealers.create(
address="xx",
business_name="Rossi Automobili S.R.L.",
city="xx",
contact_email="info@rossi-auto.it",
contact_phone="xxxxx",
postal_code="20121",
primary_domain="rossi-auto.it",
province_code="MI",
vat_number="IT01234567890",
page = await client.dealers.list(
limit=10,
status="active",
)
print(dealer_detail.dealer_id)
print(page.data)


asyncio.run(main())
Expand Down Expand Up @@ -114,18 +100,11 @@ async def main() -> None:
api_key=os.environ.get("PARTNERMAX_API_KEY"), # This is the default and can be omitted
http_client=DefaultAioHttpClient(),
) as client:
dealer_detail = await client.dealers.create(
address="xx",
business_name="Rossi Automobili S.R.L.",
city="xx",
contact_email="info@rossi-auto.it",
contact_phone="xxxxx",
postal_code="20121",
primary_domain="rossi-auto.it",
province_code="MI",
vat_number="IT01234567890",
page = await client.dealers.list(
limit=10,
status="active",
)
print(dealer_detail.dealer_id)
print(page.data)


asyncio.run(main())
Expand All @@ -140,6 +119,81 @@ Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typ

Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.

## Pagination

List methods in the Partnermax API are paginated.

This library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually:

```python
from partnermax import Partnermax

client = Partnermax()

all_dealers = []
# Automatically fetches more pages as needed.
for dealer in client.dealers.list(
limit=10,
status="active",
):
# Do something with dealer here
all_dealers.append(dealer)
print(all_dealers)
```

Or, asynchronously:

```python
import asyncio
from partnermax import AsyncPartnermax

client = AsyncPartnermax()


async def main() -> None:
all_dealers = []
# Iterate through items across all pages, issuing requests as needed.
async for dealer in client.dealers.list(
limit=10,
status="active",
):
all_dealers.append(dealer)
print(all_dealers)


asyncio.run(main())
```

Alternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages:

```python
first_page = await client.dealers.list(
limit=10,
status="active",
)
if first_page.has_next_page():
print(f"will fetch next page using these details: {first_page.next_page_info()}")
next_page = await first_page.get_next_page()
print(f"number of items we just fetched: {len(next_page.data)}")

# Remove `await` for non-async usage.
```

Or just work directly with the returned data:

```python
first_page = await client.dealers.list(
limit=10,
status="active",
)

print(f"next page cursor: {first_page.next_cursor}") # => "next page cursor: ..."
for dealer in first_page.data:
print(dealer.dealer_id)

# Remove `await` for non-async usage.
```

## Nested params

Nested parameters are dictionaries, typed using `TypedDict`, for example:
Expand Down Expand Up @@ -297,7 +351,7 @@ response = client.dealers.with_raw_response.list()
print(response.headers.get('X-My-Header'))

dealer = response.parse() # get the object that `dealers.list()` would have returned
print(dealer.data)
print(dealer.dealer_id)
```

These methods return an [`APIResponse`](https://github.com/DealerMax-app/partnermax-python/tree/main/src/partnermax/_response.py) object.
Expand Down
11 changes: 5 additions & 6 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,14 @@ Methods:
Types:

```python
from partnermax.types import DealerDetail, DealerSummary, DealerListResponse
from partnermax.types import DealerDetail, DealerSummary
```

Methods:

- <code title="post /v1/dealers">client.dealers.<a href="./src/partnermax/resources/dealers/dealers.py">create</a>(\*\*<a href="src/partnermax/types/dealer_create_params.py">params</a>) -> <a href="./src/partnermax/types/dealer_detail.py">DealerDetail</a></code>
- <code title="get /v1/dealers/{dealer_id}">client.dealers.<a href="./src/partnermax/resources/dealers/dealers.py">retrieve</a>(dealer_id) -> <a href="./src/partnermax/types/dealer_detail.py">DealerDetail</a></code>
- <code title="patch /v1/dealers/{dealer_id}">client.dealers.<a href="./src/partnermax/resources/dealers/dealers.py">update</a>(dealer_id, \*\*<a href="src/partnermax/types/dealer_update_params.py">params</a>) -> <a href="./src/partnermax/types/dealer_detail.py">DealerDetail</a></code>
- <code title="get /v1/dealers">client.dealers.<a href="./src/partnermax/resources/dealers/dealers.py">list</a>(\*\*<a href="src/partnermax/types/dealer_list_params.py">params</a>) -> <a href="./src/partnermax/types/dealer_list_response.py">DealerListResponse</a></code>
- <code title="get /v1/dealers">client.dealers.<a href="./src/partnermax/resources/dealers/dealers.py">list</a>(\*\*<a href="src/partnermax/types/dealer_list_params.py">params</a>) -> <a href="./src/partnermax/types/dealer_summary.py">SyncCursorPage[DealerSummary]</a></code>
- <code title="delete /v1/dealers/{dealer_id}">client.dealers.<a href="./src/partnermax/resources/dealers/dealers.py">delete</a>(dealer_id) -> None</code>

## NltSettings
Expand All @@ -48,13 +47,13 @@ Methods:
Types:

```python
from partnermax.types.dealers.nlt import NltOfferSummary, OfferRetrieveResponse, OfferListResponse
from partnermax.types.dealers.nlt import NltOfferSummary, OfferRetrieveResponse
```

Methods:

- <code title="get /v1/dealers/{dealer_id}/nlt/offers/{offer_id}">client.dealers.nlt.offers.<a href="./src/partnermax/resources/dealers/nlt/offers.py">retrieve</a>(offer_id, \*, dealer_id) -> <a href="./src/partnermax/types/dealers/nlt/offer_retrieve_response.py">OfferRetrieveResponse</a></code>
- <code title="get /v1/dealers/{dealer_id}/nlt/offers">client.dealers.nlt.offers.<a href="./src/partnermax/resources/dealers/nlt/offers.py">list</a>(dealer_id, \*\*<a href="src/partnermax/types/dealers/nlt/offer_list_params.py">params</a>) -> <a href="./src/partnermax/types/dealers/nlt/offer_list_response.py">OfferListResponse</a></code>
- <code title="get /v1/dealers/{dealer_id}/nlt/offers">client.dealers.nlt.offers.<a href="./src/partnermax/resources/dealers/nlt/offers.py">list</a>(dealer_id, \*\*<a href="src/partnermax/types/dealers/nlt/offer_list_params.py">params</a>) -> <a href="./src/partnermax/types/dealers/nlt/nlt_offer_summary.py">SyncCursorPage[NltOfferSummary]</a></code>

## Vehicles

Expand All @@ -76,7 +75,7 @@ Methods:
- <code title="post /v1/dealers/{dealer_id}/vehicles">client.dealers.vehicles.<a href="./src/partnermax/resources/dealers/vehicles/vehicles.py">create</a>(dealer_id, \*\*<a href="src/partnermax/types/dealers/vehicle_create_params.py">params</a>) -> <a href="./src/partnermax/types/dealers/vehicle_detail.py">VehicleDetail</a></code>
- <code title="get /v1/dealers/{dealer_id}/vehicles/{vehicle_id}">client.dealers.vehicles.<a href="./src/partnermax/resources/dealers/vehicles/vehicles.py">retrieve</a>(vehicle_id, \*, dealer_id, \*\*<a href="src/partnermax/types/dealers/vehicle_retrieve_params.py">params</a>) -> <a href="./src/partnermax/types/dealers/vehicle_detail.py">VehicleDetail</a></code>
- <code title="patch /v1/dealers/{dealer_id}/vehicles/{vehicle_id}">client.dealers.vehicles.<a href="./src/partnermax/resources/dealers/vehicles/vehicles.py">update</a>(vehicle_id, \*, dealer_id, \*\*<a href="src/partnermax/types/dealers/vehicle_update_params.py">params</a>) -> <a href="./src/partnermax/types/dealers/vehicle_detail.py">VehicleDetail</a></code>
- <code title="get /v1/dealers/{dealer_id}/vehicles">client.dealers.vehicles.<a href="./src/partnermax/resources/dealers/vehicles/vehicles.py">list</a>(dealer_id, \*\*<a href="src/partnermax/types/dealers/vehicle_list_params.py">params</a>) -> <a href="./src/partnermax/types/dealers/vehicle_list.py">VehicleList</a></code>
- <code title="get /v1/dealers/{dealer_id}/vehicles">client.dealers.vehicles.<a href="./src/partnermax/resources/dealers/vehicles/vehicles.py">list</a>(dealer_id, \*\*<a href="src/partnermax/types/dealers/vehicle_list_params.py">params</a>) -> <a href="./src/partnermax/types/dealers/vehicle_summary.py">SyncCursorPage[VehicleSummary]</a></code>
- <code title="delete /v1/dealers/{dealer_id}/vehicles/{vehicle_id}">client.dealers.vehicles.<a href="./src/partnermax/resources/dealers/vehicles/vehicles.py">delete</a>(vehicle_id, \*, dealer_id) -> None</code>
- <code title="post /v1/dealers/{dealer_id}/vehicles/bulk">client.dealers.vehicles.<a href="./src/partnermax/resources/dealers/vehicles/vehicles.py">bulk</a>(dealer_id, \*\*<a href="src/partnermax/types/dealers/vehicle_bulk_params.py">params</a>) -> <a href="./src/partnermax/types/dealers/bulk_create_vehicles_response.py">BulkCreateVehiclesResponse</a></code>

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "partnermax"
version = "0.11.0"
version = "0.11.1"
description = "The official Python library for the partnermax API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand Down
24 changes: 12 additions & 12 deletions src/partnermax/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,9 @@ def __init__(

@cached_property
def keys(self) -> KeysResource:
"""API key lifecycle management — issue, list, revoke.
"""API key lifecycle management.

The partner authenticates every request with `X-Api-Key` (preferred) or `Authorization: Bearer <key>`; the server identifies the partner from the key and scopes all reads/writes to dealers owned by that partner.
PartnerMAX v1 allows one active API key per partner/environment; partners authenticate every request with `X-Api-Key` (preferred) or `Authorization: Bearer <key>`, and replacement is handled through DealerMAX support.
"""
from .resources.keys import KeysResource

Expand Down Expand Up @@ -410,9 +410,9 @@ def __init__(

@cached_property
def keys(self) -> AsyncKeysResource:
"""API key lifecycle management — issue, list, revoke.
"""API key lifecycle management.

The partner authenticates every request with `X-Api-Key` (preferred) or `Authorization: Bearer <key>`; the server identifies the partner from the key and scopes all reads/writes to dealers owned by that partner.
PartnerMAX v1 allows one active API key per partner/environment; partners authenticate every request with `X-Api-Key` (preferred) or `Authorization: Bearer <key>`, and replacement is handled through DealerMAX support.
"""
from .resources.keys import AsyncKeysResource

Expand Down Expand Up @@ -581,9 +581,9 @@ def __init__(self, client: Partnermax) -> None:

@cached_property
def keys(self) -> keys.KeysResourceWithRawResponse:
"""API key lifecycle management — issue, list, revoke.
"""API key lifecycle management.

The partner authenticates every request with `X-Api-Key` (preferred) or `Authorization: Bearer <key>`; the server identifies the partner from the key and scopes all reads/writes to dealers owned by that partner.
PartnerMAX v1 allows one active API key per partner/environment; partners authenticate every request with `X-Api-Key` (preferred) or `Authorization: Bearer <key>`, and replacement is handled through DealerMAX support.
"""
from .resources.keys import KeysResourceWithRawResponse

Expand All @@ -605,9 +605,9 @@ def __init__(self, client: AsyncPartnermax) -> None:

@cached_property
def keys(self) -> keys.AsyncKeysResourceWithRawResponse:
"""API key lifecycle management — issue, list, revoke.
"""API key lifecycle management.

The partner authenticates every request with `X-Api-Key` (preferred) or `Authorization: Bearer <key>`; the server identifies the partner from the key and scopes all reads/writes to dealers owned by that partner.
PartnerMAX v1 allows one active API key per partner/environment; partners authenticate every request with `X-Api-Key` (preferred) or `Authorization: Bearer <key>`, and replacement is handled through DealerMAX support.
"""
from .resources.keys import AsyncKeysResourceWithRawResponse

Expand All @@ -629,9 +629,9 @@ def __init__(self, client: Partnermax) -> None:

@cached_property
def keys(self) -> keys.KeysResourceWithStreamingResponse:
"""API key lifecycle management — issue, list, revoke.
"""API key lifecycle management.

The partner authenticates every request with `X-Api-Key` (preferred) or `Authorization: Bearer <key>`; the server identifies the partner from the key and scopes all reads/writes to dealers owned by that partner.
PartnerMAX v1 allows one active API key per partner/environment; partners authenticate every request with `X-Api-Key` (preferred) or `Authorization: Bearer <key>`, and replacement is handled through DealerMAX support.
"""
from .resources.keys import KeysResourceWithStreamingResponse

Expand All @@ -653,9 +653,9 @@ def __init__(self, client: AsyncPartnermax) -> None:

@cached_property
def keys(self) -> keys.AsyncKeysResourceWithStreamingResponse:
"""API key lifecycle management — issue, list, revoke.
"""API key lifecycle management.

The partner authenticates every request with `X-Api-Key` (preferred) or `Authorization: Bearer <key>`; the server identifies the partner from the key and scopes all reads/writes to dealers owned by that partner.
PartnerMAX v1 allows one active API key per partner/environment; partners authenticate every request with `X-Api-Key` (preferred) or `Authorization: Bearer <key>`, and replacement is handled through DealerMAX support.
"""
from .resources.keys import AsyncKeysResourceWithStreamingResponse

Expand Down
2 changes: 1 addition & 1 deletion src/partnermax/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

__title__ = "partnermax"
__version__ = "0.11.0" # x-release-please-version
__version__ = "0.11.1" # x-release-please-version
68 changes: 68 additions & 0 deletions src/partnermax/pagination.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from typing import List, Generic, TypeVar, Optional
from typing_extensions import override

from ._base_client import BasePage, PageInfo, BaseSyncPage, BaseAsyncPage

__all__ = ["SyncCursorPage", "AsyncCursorPage"]

_T = TypeVar("_T")


class SyncCursorPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
data: List[_T]
has_more: Optional[bool] = None
next_cursor: Optional[str] = None

@override
def _get_page_items(self) -> List[_T]:
data = self.data
if not data:
return []
return data

@override
def has_next_page(self) -> bool:
has_more = self.has_more
if has_more is not None and has_more is False:
return False

return super().has_next_page()

@override
def next_page_info(self) -> Optional[PageInfo]:
next_cursor = self.next_cursor
if not next_cursor:
return None

return PageInfo(params={"cursor": next_cursor})


class AsyncCursorPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]):
data: List[_T]
has_more: Optional[bool] = None
next_cursor: Optional[str] = None

@override
def _get_page_items(self) -> List[_T]:
data = self.data
if not data:
return []
return data

@override
def has_next_page(self) -> bool:
has_more = self.has_more
if has_more is not None and has_more is False:
return False

return super().has_next_page()

@override
def next_page_info(self) -> Optional[PageInfo]:
next_cursor = self.next_cursor
if not next_cursor:
return None

return PageInfo(params={"cursor": next_cursor})
Loading
Loading