diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 6d78745..091cfb1 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.9.0"
+ ".": "0.10.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index 9de5f99..cef3e65 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 21
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/azure/partnermax-5a0409bb0fddcda8df26a189afdb3328c0402ce1385e56c4793e2969efd2b290.yml
-openapi_spec_hash: fa78b80fb8127ab4e7761cbf9ccbbdd2
-config_hash: 84dd1a86856c12a806c07e9e23badbfd
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/azure/partnermax-aee817a9450d1094d357a560cebc1c876863fb7d1c712efaf2509a567cd55954.yml
+openapi_spec_hash: 6f576691201740bbee9e1f7f97bdd9b0
+config_hash: 18c6c7df17bad3320b9f2c126947f00a
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5412df1..009af4c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+## 0.10.0 (2026-05-18)
+
+Full Changelog: [v0.9.0...v0.10.0](https://github.com/DealerMax-app/partnermax-python/compare/v0.9.0...v0.10.0)
+
+### Features
+
+* **vehicles:** used-vehicle CRUD + bulk insert for v1.1.0 ([85e4b4f](https://github.com/DealerMax-app/partnermax-python/commit/85e4b4fb69db79b37dbb528c403763138d147ce4))
+
## 0.9.0 (2026-05-18)
Full Changelog: [v0.8.0...v0.9.0](https://github.com/DealerMax-app/partnermax-python/compare/v0.8.0...v0.9.0)
diff --git a/api.md b/api.md
index cb3ea5d..1b965c3 100644
--- a/api.md
+++ b/api.md
@@ -62,6 +62,7 @@ Types:
```python
from partnermax.types.dealers import (
+ AIContent,
BulkCreateVehiclesResponse,
BulkRowOutcome,
VehicleDetail,
diff --git a/pyproject.toml b/pyproject.toml
index a1e3262..3a90c52 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "partnermax"
-version = "0.9.0"
+version = "0.10.0"
description = "The official Python library for the partnermax API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/partnermax/_version.py b/src/partnermax/_version.py
index f52be1e..a5b18a0 100644
--- a/src/partnermax/_version.py
+++ b/src/partnermax/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "partnermax"
-__version__ = "0.9.0" # x-release-please-version
+__version__ = "0.10.0" # x-release-please-version
diff --git a/src/partnermax/resources/dealers/vehicles/vehicles.py b/src/partnermax/resources/dealers/vehicles/vehicles.py
index f0c5a58..424941e 100644
--- a/src/partnermax/resources/dealers/vehicles/vehicles.py
+++ b/src/partnermax/resources/dealers/vehicles/vehicles.py
@@ -2,8 +2,7 @@
from __future__ import annotations
-from typing import Union, Iterable, Optional
-from datetime import date
+from typing import Iterable, Optional
import httpx
@@ -78,7 +77,6 @@ def create(
dealer_id: str,
*,
certified_km: int,
- cost_price_eur: float,
motornet_code: str,
plate: str,
registration_year: int,
@@ -88,17 +86,10 @@ def create(
description: str | Omit = omit,
extended_warranty_enabled: bool | Omit = omit,
extended_warranty_months: Optional[int] | Omit = omit,
- inspection_expiry_date: Union[str, date, None] | Omit = omit,
is_for_sale: bool | Omit = omit,
is_visible: bool | Omit = omit,
- last_service_date: Union[str, date, None] | Omit = omit,
- last_service_km: Optional[int] | Omit = omit,
- last_service_notes: Optional[str] | Omit = omit,
notes: Optional[str] | Omit = omit,
- previous_owner_count: Optional[int] | Omit = omit,
- previous_ownership_transfer_date: Union[str, date, None] | Omit = omit,
registration_month: Optional[int] | Omit = omit,
- road_tax_expiry_date: Union[str, date, None] | Omit = omit,
vat_displayed: bool | Omit = omit,
vehicle_damaged: bool | Omit = omit,
vin: Optional[str] | Omit = omit,
@@ -124,9 +115,6 @@ def create(
Args:
certified_km: Certified odometer reading at intake, in kilometres.
- cost_price_eur: Cost basis to the dealer in EUR (partner/dealer internal). Not surfaced on
- consumer-facing AI surfaces; used by dealer reporting and margin analytics only.
-
motornet_code: Motornet UNI code identifying the exact vehicle configuration. Must exist in
`mnet_dettagli_usato` at submission time; otherwise the call returns 422
`motornet_code_not_in_catalogue`. The partner is expected to source this from
@@ -151,8 +139,6 @@ def create(
notes: Free-form short notes; surfaced as `mnet_dettagli.precisazioni`-style.
- previous_ownership_transfer_date: Date of the most recent ownership transfer, if known.
-
registration_month: Month of registration (1–12).
vat_displayed: If true the public price is displayed VAT-exposed (B2B); otherwise VAT-inclusive
@@ -176,7 +162,6 @@ def create(
body=maybe_transform(
{
"certified_km": certified_km,
- "cost_price_eur": cost_price_eur,
"motornet_code": motornet_code,
"plate": plate,
"registration_year": registration_year,
@@ -186,17 +171,10 @@ def create(
"description": description,
"extended_warranty_enabled": extended_warranty_enabled,
"extended_warranty_months": extended_warranty_months,
- "inspection_expiry_date": inspection_expiry_date,
"is_for_sale": is_for_sale,
"is_visible": is_visible,
- "last_service_date": last_service_date,
- "last_service_km": last_service_km,
- "last_service_notes": last_service_notes,
"notes": notes,
- "previous_owner_count": previous_owner_count,
- "previous_ownership_transfer_date": previous_ownership_transfer_date,
"registration_month": registration_month,
- "road_tax_expiry_date": road_tax_expiry_date,
"vat_displayed": vat_displayed,
"vehicle_damaged": vehicle_damaged,
"vin": vin,
@@ -264,21 +242,13 @@ def update(
alloy_wheel_size: Optional[int] | Omit = omit,
certified_km: Optional[int] | Omit = omit,
color: Optional[str] | Omit = omit,
- cost_price_eur: Optional[float] | Omit = omit,
description: Optional[str] | Omit = omit,
extended_warranty_enabled: Optional[bool] | Omit = omit,
extended_warranty_months: Optional[int] | Omit = omit,
- inspection_expiry_date: Union[str, date, None] | Omit = omit,
is_for_sale: Optional[bool] | Omit = omit,
is_visible: Optional[bool] | Omit = omit,
- last_service_date: Union[str, date, None] | Omit = omit,
- last_service_km: Optional[int] | Omit = omit,
- last_service_notes: Optional[str] | Omit = omit,
notes: Optional[str] | Omit = omit,
- previous_owner_count: Optional[int] | Omit = omit,
- previous_ownership_transfer_date: Union[str, date, None] | Omit = omit,
registration_month: Optional[int] | Omit = omit,
- road_tax_expiry_date: Union[str, date, None] | Omit = omit,
sale_price_eur: Optional[float] | Omit = omit,
vat_displayed: Optional[bool] | Omit = omit,
vehicle_damaged: Optional[bool] | Omit = omit,
@@ -318,21 +288,13 @@ def update(
"alloy_wheel_size": alloy_wheel_size,
"certified_km": certified_km,
"color": color,
- "cost_price_eur": cost_price_eur,
"description": description,
"extended_warranty_enabled": extended_warranty_enabled,
"extended_warranty_months": extended_warranty_months,
- "inspection_expiry_date": inspection_expiry_date,
"is_for_sale": is_for_sale,
"is_visible": is_visible,
- "last_service_date": last_service_date,
- "last_service_km": last_service_km,
- "last_service_notes": last_service_notes,
"notes": notes,
- "previous_owner_count": previous_owner_count,
- "previous_ownership_transfer_date": previous_ownership_transfer_date,
"registration_month": registration_month,
- "road_tax_expiry_date": road_tax_expiry_date,
"sale_price_eur": sale_price_eur,
"vat_displayed": vat_displayed,
"vehicle_damaged": vehicle_damaged,
@@ -562,7 +524,6 @@ async def create(
dealer_id: str,
*,
certified_km: int,
- cost_price_eur: float,
motornet_code: str,
plate: str,
registration_year: int,
@@ -572,17 +533,10 @@ async def create(
description: str | Omit = omit,
extended_warranty_enabled: bool | Omit = omit,
extended_warranty_months: Optional[int] | Omit = omit,
- inspection_expiry_date: Union[str, date, None] | Omit = omit,
is_for_sale: bool | Omit = omit,
is_visible: bool | Omit = omit,
- last_service_date: Union[str, date, None] | Omit = omit,
- last_service_km: Optional[int] | Omit = omit,
- last_service_notes: Optional[str] | Omit = omit,
notes: Optional[str] | Omit = omit,
- previous_owner_count: Optional[int] | Omit = omit,
- previous_ownership_transfer_date: Union[str, date, None] | Omit = omit,
registration_month: Optional[int] | Omit = omit,
- road_tax_expiry_date: Union[str, date, None] | Omit = omit,
vat_displayed: bool | Omit = omit,
vehicle_damaged: bool | Omit = omit,
vin: Optional[str] | Omit = omit,
@@ -608,9 +562,6 @@ async def create(
Args:
certified_km: Certified odometer reading at intake, in kilometres.
- cost_price_eur: Cost basis to the dealer in EUR (partner/dealer internal). Not surfaced on
- consumer-facing AI surfaces; used by dealer reporting and margin analytics only.
-
motornet_code: Motornet UNI code identifying the exact vehicle configuration. Must exist in
`mnet_dettagli_usato` at submission time; otherwise the call returns 422
`motornet_code_not_in_catalogue`. The partner is expected to source this from
@@ -635,8 +586,6 @@ async def create(
notes: Free-form short notes; surfaced as `mnet_dettagli.precisazioni`-style.
- previous_ownership_transfer_date: Date of the most recent ownership transfer, if known.
-
registration_month: Month of registration (1–12).
vat_displayed: If true the public price is displayed VAT-exposed (B2B); otherwise VAT-inclusive
@@ -660,7 +609,6 @@ async def create(
body=await async_maybe_transform(
{
"certified_km": certified_km,
- "cost_price_eur": cost_price_eur,
"motornet_code": motornet_code,
"plate": plate,
"registration_year": registration_year,
@@ -670,17 +618,10 @@ async def create(
"description": description,
"extended_warranty_enabled": extended_warranty_enabled,
"extended_warranty_months": extended_warranty_months,
- "inspection_expiry_date": inspection_expiry_date,
"is_for_sale": is_for_sale,
"is_visible": is_visible,
- "last_service_date": last_service_date,
- "last_service_km": last_service_km,
- "last_service_notes": last_service_notes,
"notes": notes,
- "previous_owner_count": previous_owner_count,
- "previous_ownership_transfer_date": previous_ownership_transfer_date,
"registration_month": registration_month,
- "road_tax_expiry_date": road_tax_expiry_date,
"vat_displayed": vat_displayed,
"vehicle_damaged": vehicle_damaged,
"vin": vin,
@@ -748,21 +689,13 @@ async def update(
alloy_wheel_size: Optional[int] | Omit = omit,
certified_km: Optional[int] | Omit = omit,
color: Optional[str] | Omit = omit,
- cost_price_eur: Optional[float] | Omit = omit,
description: Optional[str] | Omit = omit,
extended_warranty_enabled: Optional[bool] | Omit = omit,
extended_warranty_months: Optional[int] | Omit = omit,
- inspection_expiry_date: Union[str, date, None] | Omit = omit,
is_for_sale: Optional[bool] | Omit = omit,
is_visible: Optional[bool] | Omit = omit,
- last_service_date: Union[str, date, None] | Omit = omit,
- last_service_km: Optional[int] | Omit = omit,
- last_service_notes: Optional[str] | Omit = omit,
notes: Optional[str] | Omit = omit,
- previous_owner_count: Optional[int] | Omit = omit,
- previous_ownership_transfer_date: Union[str, date, None] | Omit = omit,
registration_month: Optional[int] | Omit = omit,
- road_tax_expiry_date: Union[str, date, None] | Omit = omit,
sale_price_eur: Optional[float] | Omit = omit,
vat_displayed: Optional[bool] | Omit = omit,
vehicle_damaged: Optional[bool] | Omit = omit,
@@ -802,21 +735,13 @@ async def update(
"alloy_wheel_size": alloy_wheel_size,
"certified_km": certified_km,
"color": color,
- "cost_price_eur": cost_price_eur,
"description": description,
"extended_warranty_enabled": extended_warranty_enabled,
"extended_warranty_months": extended_warranty_months,
- "inspection_expiry_date": inspection_expiry_date,
"is_for_sale": is_for_sale,
"is_visible": is_visible,
- "last_service_date": last_service_date,
- "last_service_km": last_service_km,
- "last_service_notes": last_service_notes,
"notes": notes,
- "previous_owner_count": previous_owner_count,
- "previous_ownership_transfer_date": previous_ownership_transfer_date,
"registration_month": registration_month,
- "road_tax_expiry_date": road_tax_expiry_date,
"sale_price_eur": sale_price_eur,
"vat_displayed": vat_displayed,
"vehicle_damaged": vehicle_damaged,
diff --git a/src/partnermax/types/dealers/__init__.py b/src/partnermax/types/dealers/__init__.py
index f97da52..9e42df0 100644
--- a/src/partnermax/types/dealers/__init__.py
+++ b/src/partnermax/types/dealers/__init__.py
@@ -2,6 +2,7 @@
from __future__ import annotations
+from .ai_content import AIContent as AIContent
from .nlt_settings import NltSettings as NltSettings
from .vehicle_list import VehicleList as VehicleList
from .vehicle_detail import VehicleDetail as VehicleDetail
diff --git a/src/partnermax/types/dealers/ai_content.py b/src/partnermax/types/dealers/ai_content.py
new file mode 100644
index 0000000..a7eb24d
--- /dev/null
+++ b/src/partnermax/types/dealers/ai_content.py
@@ -0,0 +1,65 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, List, Optional
+from datetime import datetime
+
+from ..._models import BaseModel
+
+__all__ = ["AIContent"]
+
+
+class AIContent(BaseModel):
+ """AI-generated editorial content for a single vehicle.
+
+ Produced asynchronously by the ``usato_ai_content_worker`` in
+ ``azurenet-engine`` within ~60 seconds of vehicle creation. While the
+ worker is still pending, every field is ``null``; once the worker
+ completes the row this object carries the full editorial set the
+ cross-network AI consumers (MCP, ChatGPT Custom GPT, NLWeb) display.
+
+ Layered descriptions:
+
+ * ``tagline`` — 8–12 word headline. Use on listing cards / push notifications.
+ * ``short`` — 1–2 sentence summary (≤ 220 chars). Use as the meta description fallback.
+ * ``medium`` — paragraph (~400 chars). Use on vehicle-detail SEO blurbs.
+ * ``long`` — full marketing description (1500–3000 chars). Use on detail pages.
+ * ``highlights`` — array of 3–7 selling points. Render as a bullet list above the description.
+ * ``faq`` — array of ``{question, answer}`` objects. Render as accordion / JSON-LD ``FAQPage``.
+ * ``seo_title`` — ≤ 60 chars, ``
``-ready.
+ * ``seo_description`` — ≤ 160 chars, meta description-ready.
+ * ``slug`` — URL-safe slug used in the canonical URL on the dealer site.
+
+ The Italian language is canonical (``lang='it'``). Multi-language is
+ on the roadmap; until then the partner gets exactly what the
+ consumer AI surfaces get.
+ """
+
+ faq: Optional[List[Dict[str, str]]] = None
+ """Array of `{question, answer}` objects.
+
+ Each entry has two string keys; render with the partner's own FAQ UI or feed
+ into a `FAQPage` JSON-LD block.
+ """
+
+ generated_at: Optional[datetime] = None
+ """UTC timestamp of the most recent AI generation.
+
+ `null` until the worker first processes the vehicle (≤ 60 seconds after vehicle
+ creation).
+ """
+
+ highlights: Optional[List[str]] = None
+
+ long: Optional[str] = None
+
+ medium: Optional[str] = None
+
+ seo_description: Optional[str] = None
+
+ seo_title: Optional[str] = None
+
+ short: Optional[str] = None
+
+ slug: Optional[str] = None
+
+ tagline: Optional[str] = None
diff --git a/src/partnermax/types/dealers/bulk_row_outcome.py b/src/partnermax/types/dealers/bulk_row_outcome.py
index e3b6cb7..83d8b98 100644
--- a/src/partnermax/types/dealers/bulk_row_outcome.py
+++ b/src/partnermax/types/dealers/bulk_row_outcome.py
@@ -39,9 +39,22 @@ class BulkRowOutcome(BaseModel):
Returned by `GET /v1/dealers/{id}/vehicles/{id}`,
`POST /v1/dealers/{id}/vehicles`, and `PATCH /v1/dealers/{id}/vehicles/{id}`.
- `technical_details` carries the flat Motornet specs dict (Italian column names
- as keys: `cilindrata`, `kw`, `hp`, `lunghezza`, `consumo_medio`,
- `emissioni_co2`, etc.). Same shape conventions as `NltOfferDetail`
- (`feedback_partnermax_field_naming_us_english`: field names are English
- snake_case, raw catalogue values stay verbatim).
+ Carries three layers of information:
+
+ - **Partner-supplied** — what the partner posted (`plate`, `description`,
+ `sale_price_eur`, etc.).
+ - **Catalogue-derived** — `technical_details` is the flat `mnet_dettagli_usato`
+ dict (Italian column keys: `cilindrata`, `kw`, `hp`, `lunghezza`,
+ `consumo_medio`, `emissioni_co2`, etc.). Same shape conventions as
+ `NltOfferDetail` per `feedback_partnermax_field_naming_us_english`.
+ - **AI-derived** — `ai_content` carries the editorial output the cross-network
+ consumers display (descriptions, highlights, FAQ, SEO meta). `null` until the
+ worker has processed the vehicle.
+
+ Fields the partner does NOT see through this surface (because they are
+ dealer-internal margin/operations data the partner does not own):
+ `cost_price_eur`, `inspection_expiry_date`, `road_tax_expiry_date`,
+ `previous_owner_count`, `previous_ownership_transfer_date`, `last_service_*`.
+ These exist in the underlying DB tables for the DealerMAX dashboard but are
+ intentionally not exposed via the SDK.
"""
diff --git a/src/partnermax/types/dealers/vehicle_bulk_params.py b/src/partnermax/types/dealers/vehicle_bulk_params.py
index 38d9fcb..35578ad 100644
--- a/src/partnermax/types/dealers/vehicle_bulk_params.py
+++ b/src/partnermax/types/dealers/vehicle_bulk_params.py
@@ -2,8 +2,7 @@
from __future__ import annotations
-from typing import Union, Iterable, Optional
-from datetime import date
+from typing import Iterable, Optional
from typing_extensions import Required, Annotated, TypedDict
from ..._utils import PropertyInfo
@@ -40,13 +39,6 @@ class Vehicle(TypedDict, total=False):
certified_km: Required[int]
"""Certified odometer reading at intake, in kilometres."""
- cost_price_eur: Required[float]
- """Cost basis to the dealer in EUR (partner/dealer internal).
-
- Not surfaced on consumer-facing AI surfaces; used by dealer reporting and margin
- analytics only.
- """
-
motornet_code: Required[str]
"""Motornet UNI code identifying the exact vehicle configuration.
@@ -84,8 +76,6 @@ class Vehicle(TypedDict, total=False):
extended_warranty_months: Optional[int]
- inspection_expiry_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")]
-
is_for_sale: bool
"""Maps to `azlease_usatoauto.is_vendita_enabled`.
@@ -99,25 +89,12 @@ class Vehicle(TypedDict, total=False):
surfaces. Maps to `azlease_usatoin.visibile`.
"""
- last_service_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")]
-
- last_service_km: Optional[int]
-
- last_service_notes: Optional[str]
-
notes: Optional[str]
"""Free-form short notes; surfaced as `mnet_dettagli.precisazioni`-style."""
- previous_owner_count: Optional[int]
-
- previous_ownership_transfer_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")]
- """Date of the most recent ownership transfer, if known."""
-
registration_month: Optional[int]
"""Month of registration (1–12)."""
- road_tax_expiry_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")]
-
vat_displayed: bool
"""
If true the public price is displayed VAT-exposed (B2B); otherwise VAT-inclusive
diff --git a/src/partnermax/types/dealers/vehicle_create_params.py b/src/partnermax/types/dealers/vehicle_create_params.py
index ed80776..6dfda24 100644
--- a/src/partnermax/types/dealers/vehicle_create_params.py
+++ b/src/partnermax/types/dealers/vehicle_create_params.py
@@ -2,8 +2,7 @@
from __future__ import annotations
-from typing import Union, Optional
-from datetime import date
+from typing import Optional
from typing_extensions import Required, Annotated, TypedDict
from ..._utils import PropertyInfo
@@ -15,13 +14,6 @@ class VehicleCreateParams(TypedDict, total=False):
certified_km: Required[int]
"""Certified odometer reading at intake, in kilometres."""
- cost_price_eur: Required[float]
- """Cost basis to the dealer in EUR (partner/dealer internal).
-
- Not surfaced on consumer-facing AI surfaces; used by dealer reporting and margin
- analytics only.
- """
-
motornet_code: Required[str]
"""Motornet UNI code identifying the exact vehicle configuration.
@@ -59,8 +51,6 @@ class VehicleCreateParams(TypedDict, total=False):
extended_warranty_months: Optional[int]
- inspection_expiry_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")]
-
is_for_sale: bool
"""Maps to `azlease_usatoauto.is_vendita_enabled`.
@@ -74,25 +64,12 @@ class VehicleCreateParams(TypedDict, total=False):
surfaces. Maps to `azlease_usatoin.visibile`.
"""
- last_service_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")]
-
- last_service_km: Optional[int]
-
- last_service_notes: Optional[str]
-
notes: Optional[str]
"""Free-form short notes; surfaced as `mnet_dettagli.precisazioni`-style."""
- previous_owner_count: Optional[int]
-
- previous_ownership_transfer_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")]
- """Date of the most recent ownership transfer, if known."""
-
registration_month: Optional[int]
"""Month of registration (1–12)."""
- road_tax_expiry_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")]
-
vat_displayed: bool
"""
If true the public price is displayed VAT-exposed (B2B); otherwise VAT-inclusive
diff --git a/src/partnermax/types/dealers/vehicle_detail.py b/src/partnermax/types/dealers/vehicle_detail.py
index e25fce1..a243d04 100644
--- a/src/partnermax/types/dealers/vehicle_detail.py
+++ b/src/partnermax/types/dealers/vehicle_detail.py
@@ -1,9 +1,10 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Dict, List, Optional
-from datetime import date, datetime
+from datetime import datetime
from ..._models import BaseModel
+from .ai_content import AIContent
__all__ = ["VehicleDetail"]
@@ -14,17 +15,29 @@ class VehicleDetail(BaseModel):
Returned by `GET /v1/dealers/{id}/vehicles/{id}`,
`POST /v1/dealers/{id}/vehicles`, and `PATCH /v1/dealers/{id}/vehicles/{id}`.
- `technical_details` carries the flat Motornet specs dict (Italian column
- names as keys: `cilindrata`, `kw`, `hp`, `lunghezza`, `consumo_medio`,
- `emissioni_co2`, etc.). Same shape conventions as `NltOfferDetail`
- (`feedback_partnermax_field_naming_us_english`: field names are
- English snake_case, raw catalogue values stay verbatim).
+ Carries three layers of information:
+
+ * **Partner-supplied** — what the partner posted (``plate``, ``description``,
+ ``sale_price_eur``, etc.).
+ * **Catalogue-derived** — ``technical_details`` is the flat
+ ``mnet_dettagli_usato`` dict (Italian column keys: ``cilindrata``, ``kw``,
+ ``hp``, ``lunghezza``, ``consumo_medio``, ``emissioni_co2``, etc.).
+ Same shape conventions as ``NltOfferDetail`` per
+ ``feedback_partnermax_field_naming_us_english``.
+ * **AI-derived** — ``ai_content`` carries the editorial output the
+ cross-network consumers display (descriptions, highlights, FAQ,
+ SEO meta). ``null`` until the worker has processed the vehicle.
+
+ Fields the partner does NOT see through this surface (because they
+ are dealer-internal margin/operations data the partner does not own):
+ ``cost_price_eur``, ``inspection_expiry_date``, ``road_tax_expiry_date``,
+ ``previous_owner_count``, ``previous_ownership_transfer_date``,
+ ``last_service_*``. These exist in the underlying DB tables for the
+ DealerMAX dashboard but are intentionally not exposed via the SDK.
"""
certified_km: int
- cost_price_eur: float
-
created_at: datetime
dealer_id: str
@@ -55,6 +68,13 @@ class VehicleDetail(BaseModel):
vehicle_id: str
+ ai_content: Optional[AIContent] = None
+ """Editorial content generated by the partnermax AI pipeline.
+
+ `null` immediately after `POST` until the worker has produced the row (≤ 60
+ seconds). Populated for the same consumer-AI surfaces (MCP, Custom GPT, NLWeb).
+ """
+
alloy_wheel_size: Optional[int] = None
brand: Optional[str] = None
@@ -66,28 +86,18 @@ class VehicleDetail(BaseModel):
fuel_type: Optional[str] = None
image_urls: Optional[List[str]] = None
- """Vehicle photos. Empty in v1 (media upload ships in v1.2)."""
-
- inspection_expiry_date: Optional[date] = None
-
- last_service_date: Optional[date] = None
+ """Vehicle photos in display order.
- last_service_km: Optional[int] = None
-
- last_service_notes: Optional[str] = None
+ The first entry is the cover photo (`position=1` in the dedicated images
+ endpoint).
+ """
model: Optional[str] = None
notes: Optional[str] = None
- previous_owner_count: Optional[int] = None
-
- previous_ownership_transfer_date: Optional[date] = None
-
registration_month: Optional[int] = None
- road_tax_expiry_date: Optional[date] = None
-
technical_details: Optional[Dict[str, object]] = None
"""
Flat dict of every non-null `mnet_dettagli_usato` column for this
diff --git a/src/partnermax/types/dealers/vehicle_update_params.py b/src/partnermax/types/dealers/vehicle_update_params.py
index 5707c59..eaa57da 100644
--- a/src/partnermax/types/dealers/vehicle_update_params.py
+++ b/src/partnermax/types/dealers/vehicle_update_params.py
@@ -2,8 +2,7 @@
from __future__ import annotations
-from typing import Union, Optional
-from datetime import date
+from typing import Optional
from typing_extensions import Required, Annotated, TypedDict
from ..._utils import PropertyInfo
@@ -20,36 +19,20 @@ class VehicleUpdateParams(TypedDict, total=False):
color: Optional[str]
- cost_price_eur: Optional[float]
-
description: Optional[str]
extended_warranty_enabled: Optional[bool]
extended_warranty_months: Optional[int]
- inspection_expiry_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")]
-
is_for_sale: Optional[bool]
is_visible: Optional[bool]
- last_service_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")]
-
- last_service_km: Optional[int]
-
- last_service_notes: Optional[str]
-
notes: Optional[str]
- previous_owner_count: Optional[int]
-
- previous_ownership_transfer_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")]
-
registration_month: Optional[int]
- road_tax_expiry_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")]
-
sale_price_eur: Optional[float]
vat_displayed: Optional[bool]
diff --git a/tests/api_resources/dealers/test_vehicles.py b/tests/api_resources/dealers/test_vehicles.py
index 53f0af6..ddd1183 100644
--- a/tests/api_resources/dealers/test_vehicles.py
+++ b/tests/api_resources/dealers/test_vehicles.py
@@ -9,7 +9,6 @@
from partnermax import Partnermax, AsyncPartnermax
from tests.utils import assert_matches_type
-from partnermax._utils import parse_date
from partnermax.types.dealers import (
VehicleList,
VehicleDetail,
@@ -28,7 +27,6 @@ def test_method_create(self, client: Partnermax) -> None:
vehicle = client.dealers.vehicles.create(
dealer_id="dealer_id",
certified_km=0,
- cost_price_eur=100,
motornet_code="xxxx",
plate="26F1KLZN",
registration_year=1960,
@@ -42,7 +40,6 @@ def test_method_create_with_all_params(self, client: Partnermax) -> None:
vehicle = client.dealers.vehicles.create(
dealer_id="dealer_id",
certified_km=0,
- cost_price_eur=100,
motornet_code="xxxx",
plate="26F1KLZN",
registration_year=1960,
@@ -52,17 +49,10 @@ def test_method_create_with_all_params(self, client: Partnermax) -> None:
description="description",
extended_warranty_enabled=True,
extended_warranty_months=1,
- inspection_expiry_date=parse_date("2019-12-27"),
is_for_sale=True,
is_visible=True,
- last_service_date=parse_date("2019-12-27"),
- last_service_km=0,
- last_service_notes="last_service_notes",
notes="notes",
- previous_owner_count=0,
- previous_ownership_transfer_date=parse_date("2019-12-27"),
registration_month=1,
- road_tax_expiry_date=parse_date("2019-12-27"),
vat_displayed=True,
vehicle_damaged=True,
vin="PTNLCJPPNYGP316PJ",
@@ -76,7 +66,6 @@ def test_raw_response_create(self, client: Partnermax) -> None:
response = client.dealers.vehicles.with_raw_response.create(
dealer_id="dealer_id",
certified_km=0,
- cost_price_eur=100,
motornet_code="xxxx",
plate="26F1KLZN",
registration_year=1960,
@@ -94,7 +83,6 @@ def test_streaming_response_create(self, client: Partnermax) -> None:
with client.dealers.vehicles.with_streaming_response.create(
dealer_id="dealer_id",
certified_km=0,
- cost_price_eur=100,
motornet_code="xxxx",
plate="26F1KLZN",
registration_year=1960,
@@ -115,7 +103,6 @@ def test_path_params_create(self, client: Partnermax) -> None:
client.dealers.vehicles.with_raw_response.create(
dealer_id="",
certified_km=0,
- cost_price_eur=100,
motornet_code="xxxx",
plate="26F1KLZN",
registration_year=1960,
@@ -202,21 +189,13 @@ def test_method_update_with_all_params(self, client: Partnermax) -> None:
alloy_wheel_size=13,
certified_km=0,
color="color",
- cost_price_eur=100,
description="description",
extended_warranty_enabled=True,
extended_warranty_months=1,
- inspection_expiry_date=parse_date("2019-12-27"),
is_for_sale=True,
is_visible=True,
- last_service_date=parse_date("2019-12-27"),
- last_service_km=0,
- last_service_notes="last_service_notes",
notes="notes",
- previous_owner_count=0,
- previous_ownership_transfer_date=parse_date("2019-12-27"),
registration_month=1,
- road_tax_expiry_date=parse_date("2019-12-27"),
sale_price_eur=100,
vat_displayed=True,
vehicle_damaged=True,
@@ -382,7 +361,6 @@ def test_method_bulk(self, client: Partnermax) -> None:
vehicles=[
{
"certified_km": 0,
- "cost_price_eur": 100,
"motornet_code": "xxxx",
"plate": "26F1KLZN",
"registration_year": 1960,
@@ -400,7 +378,6 @@ def test_method_bulk_with_all_params(self, client: Partnermax) -> None:
vehicles=[
{
"certified_km": 0,
- "cost_price_eur": 100,
"motornet_code": "xxxx",
"plate": "26F1KLZN",
"registration_year": 1960,
@@ -410,17 +387,10 @@ def test_method_bulk_with_all_params(self, client: Partnermax) -> None:
"description": "description",
"extended_warranty_enabled": True,
"extended_warranty_months": 1,
- "inspection_expiry_date": parse_date("2019-12-27"),
"is_for_sale": True,
"is_visible": True,
- "last_service_date": parse_date("2019-12-27"),
- "last_service_km": 0,
- "last_service_notes": "last_service_notes",
"notes": "notes",
- "previous_owner_count": 0,
- "previous_ownership_transfer_date": parse_date("2019-12-27"),
"registration_month": 1,
- "road_tax_expiry_date": parse_date("2019-12-27"),
"vat_displayed": True,
"vehicle_damaged": True,
"vin": "PTNLCJPPNYGP316PJ",
@@ -438,7 +408,6 @@ def test_raw_response_bulk(self, client: Partnermax) -> None:
vehicles=[
{
"certified_km": 0,
- "cost_price_eur": 100,
"motornet_code": "xxxx",
"plate": "26F1KLZN",
"registration_year": 1960,
@@ -460,7 +429,6 @@ def test_streaming_response_bulk(self, client: Partnermax) -> None:
vehicles=[
{
"certified_km": 0,
- "cost_price_eur": 100,
"motornet_code": "xxxx",
"plate": "26F1KLZN",
"registration_year": 1960,
@@ -485,7 +453,6 @@ def test_path_params_bulk(self, client: Partnermax) -> None:
vehicles=[
{
"certified_km": 0,
- "cost_price_eur": 100,
"motornet_code": "xxxx",
"plate": "26F1KLZN",
"registration_year": 1960,
@@ -506,7 +473,6 @@ async def test_method_create(self, async_client: AsyncPartnermax) -> None:
vehicle = await async_client.dealers.vehicles.create(
dealer_id="dealer_id",
certified_km=0,
- cost_price_eur=100,
motornet_code="xxxx",
plate="26F1KLZN",
registration_year=1960,
@@ -520,7 +486,6 @@ async def test_method_create_with_all_params(self, async_client: AsyncPartnermax
vehicle = await async_client.dealers.vehicles.create(
dealer_id="dealer_id",
certified_km=0,
- cost_price_eur=100,
motornet_code="xxxx",
plate="26F1KLZN",
registration_year=1960,
@@ -530,17 +495,10 @@ async def test_method_create_with_all_params(self, async_client: AsyncPartnermax
description="description",
extended_warranty_enabled=True,
extended_warranty_months=1,
- inspection_expiry_date=parse_date("2019-12-27"),
is_for_sale=True,
is_visible=True,
- last_service_date=parse_date("2019-12-27"),
- last_service_km=0,
- last_service_notes="last_service_notes",
notes="notes",
- previous_owner_count=0,
- previous_ownership_transfer_date=parse_date("2019-12-27"),
registration_month=1,
- road_tax_expiry_date=parse_date("2019-12-27"),
vat_displayed=True,
vehicle_damaged=True,
vin="PTNLCJPPNYGP316PJ",
@@ -554,7 +512,6 @@ async def test_raw_response_create(self, async_client: AsyncPartnermax) -> None:
response = await async_client.dealers.vehicles.with_raw_response.create(
dealer_id="dealer_id",
certified_km=0,
- cost_price_eur=100,
motornet_code="xxxx",
plate="26F1KLZN",
registration_year=1960,
@@ -572,7 +529,6 @@ async def test_streaming_response_create(self, async_client: AsyncPartnermax) ->
async with async_client.dealers.vehicles.with_streaming_response.create(
dealer_id="dealer_id",
certified_km=0,
- cost_price_eur=100,
motornet_code="xxxx",
plate="26F1KLZN",
registration_year=1960,
@@ -593,7 +549,6 @@ async def test_path_params_create(self, async_client: AsyncPartnermax) -> None:
await async_client.dealers.vehicles.with_raw_response.create(
dealer_id="",
certified_km=0,
- cost_price_eur=100,
motornet_code="xxxx",
plate="26F1KLZN",
registration_year=1960,
@@ -680,21 +635,13 @@ async def test_method_update_with_all_params(self, async_client: AsyncPartnermax
alloy_wheel_size=13,
certified_km=0,
color="color",
- cost_price_eur=100,
description="description",
extended_warranty_enabled=True,
extended_warranty_months=1,
- inspection_expiry_date=parse_date("2019-12-27"),
is_for_sale=True,
is_visible=True,
- last_service_date=parse_date("2019-12-27"),
- last_service_km=0,
- last_service_notes="last_service_notes",
notes="notes",
- previous_owner_count=0,
- previous_ownership_transfer_date=parse_date("2019-12-27"),
registration_month=1,
- road_tax_expiry_date=parse_date("2019-12-27"),
sale_price_eur=100,
vat_displayed=True,
vehicle_damaged=True,
@@ -860,7 +807,6 @@ async def test_method_bulk(self, async_client: AsyncPartnermax) -> None:
vehicles=[
{
"certified_km": 0,
- "cost_price_eur": 100,
"motornet_code": "xxxx",
"plate": "26F1KLZN",
"registration_year": 1960,
@@ -878,7 +824,6 @@ async def test_method_bulk_with_all_params(self, async_client: AsyncPartnermax)
vehicles=[
{
"certified_km": 0,
- "cost_price_eur": 100,
"motornet_code": "xxxx",
"plate": "26F1KLZN",
"registration_year": 1960,
@@ -888,17 +833,10 @@ async def test_method_bulk_with_all_params(self, async_client: AsyncPartnermax)
"description": "description",
"extended_warranty_enabled": True,
"extended_warranty_months": 1,
- "inspection_expiry_date": parse_date("2019-12-27"),
"is_for_sale": True,
"is_visible": True,
- "last_service_date": parse_date("2019-12-27"),
- "last_service_km": 0,
- "last_service_notes": "last_service_notes",
"notes": "notes",
- "previous_owner_count": 0,
- "previous_ownership_transfer_date": parse_date("2019-12-27"),
"registration_month": 1,
- "road_tax_expiry_date": parse_date("2019-12-27"),
"vat_displayed": True,
"vehicle_damaged": True,
"vin": "PTNLCJPPNYGP316PJ",
@@ -916,7 +854,6 @@ async def test_raw_response_bulk(self, async_client: AsyncPartnermax) -> None:
vehicles=[
{
"certified_km": 0,
- "cost_price_eur": 100,
"motornet_code": "xxxx",
"plate": "26F1KLZN",
"registration_year": 1960,
@@ -938,7 +875,6 @@ async def test_streaming_response_bulk(self, async_client: AsyncPartnermax) -> N
vehicles=[
{
"certified_km": 0,
- "cost_price_eur": 100,
"motornet_code": "xxxx",
"plate": "26F1KLZN",
"registration_year": 1960,
@@ -963,7 +899,6 @@ async def test_path_params_bulk(self, async_client: AsyncPartnermax) -> None:
vehicles=[
{
"certified_km": 0,
- "cost_price_eur": 100,
"motornet_code": "xxxx",
"plate": "26F1KLZN",
"registration_year": 1960,