diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dba7e00..67cb9e35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ The file format of it is based on [Keep a Changelog](http://keepachangelog.com/e For public Changelog covering all changes done to Pipedrive’s API, webhooks and app extensions platforms, see [public Changelog](https://pipedrive.readme.io/docs/changelog) with discussion area in [Developers Community](https://devcommunity.pipedrive.com/c/documentation/changelog/19). ## [Unreleased] +### Fixed +- Fixed double-nested response schema in `GET /api/v2/products` — `data` array items were incorrectly typed as a full response wrapper object instead of the product schema +- Added missing fields to v2 product response schema: `add_time`, `update_time`, `description`, and `category` (nullable) +- Added typed properties to `prices` array items in v2 product schema: `product_id`, `price`, `currency`, `cost`, `direct_cost` (nullable), `notes` +- Fixed `BaseProduct.id`, `ProductVariation.id`, and product image `product_id` typed as `number` instead of `integer` +- Documented the `updated_since` query parameter for `GET /api/v2/products` which was supported by the API but absent from the spec +- Fixed `quantity` field type from `integer` to `number` in deal product response schema (`GET /api/v2/deals/{id}/products`) — the API supports decimal values such as `5.5` ## [33.4.0] - 2026-05-29 ### Added diff --git a/src/versions/v2/api/products-api.ts b/src/versions/v2/api/products-api.ts index dd30a397..dfd63ca7 100644 --- a/src/versions/v2/api/products-api.ts +++ b/src/versions/v2/api/products-api.ts @@ -658,11 +658,12 @@ export const ProductsApiAxiosParamCreator = function (configuration?: Configurat * @param {number} [limit] For pagination, the limit of entries to be returned. If not provided, 100 items will be returned. Please note that a maximum value of 500 is allowed. * @param {'id' | 'name' | 'add_time' | 'update_time'} [sort_by] The field to sort by. Supported fields: `id`, `name`, `add_time`, `update_time`. * @param {'asc' | 'desc'} [sort_direction] The sorting direction. Supported values: `asc`, `desc`. + * @param {string} [updated_since] If set, only products with an `update_time` later than or equal to this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z. * @param {string} [custom_fields] Comma separated string array of custom fields keys to include. If you are only interested in a particular set of custom fields, please use this parameter for a smaller response.<br/>A maximum of 15 keys is allowed. * @throws {RequiredError} */ - getProducts: async (owner_id?: number, ids?: string, filter_id?: number, cursor?: string, limit?: number, sort_by?: 'id' | 'name' | 'add_time' | 'update_time', sort_direction?: 'asc' | 'desc', custom_fields?: string, ): Promise => { + getProducts: async (owner_id?: number, ids?: string, filter_id?: number, cursor?: string, limit?: number, sort_by?: 'id' | 'name' | 'add_time' | 'update_time', sort_direction?: 'asc' | 'desc', updated_since?: string, custom_fields?: string, ): Promise => { const localVarPath = `/products`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -710,6 +711,10 @@ export const ProductsApiAxiosParamCreator = function (configuration?: Configurat localVarQueryParameter['sort_direction'] = sort_direction; } + if (updated_since !== undefined) { + localVarQueryParameter['updated_since'] = updated_since; + } + if (custom_fields !== undefined) { localVarQueryParameter['custom_fields'] = custom_fields; } @@ -1166,12 +1171,13 @@ export const ProductsApiFp = function(configuration?: Configuration) { * @param {number} [limit] For pagination, the limit of entries to be returned. If not provided, 100 items will be returned. Please note that a maximum value of 500 is allowed. * @param {'id' | 'name' | 'add_time' | 'update_time'} [sort_by] The field to sort by. Supported fields: `id`, `name`, `add_time`, `update_time`. * @param {'asc' | 'desc'} [sort_direction] The sorting direction. Supported values: `asc`, `desc`. + * @param {string} [updated_since] If set, only products with an `update_time` later than or equal to this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z. * @param {string} [custom_fields] Comma separated string array of custom fields keys to include. If you are only interested in a particular set of custom fields, please use this parameter for a smaller response.<br/>A maximum of 15 keys is allowed. * @throws {RequiredError} */ - async getProducts(owner_id?: number, ids?: string, filter_id?: number, cursor?: string, limit?: number, sort_by?: 'id' | 'name' | 'add_time' | 'update_time', sort_direction?: 'asc' | 'desc', custom_fields?: string, ): Promise<(axios?: AxiosInstance, basePath?: string) => Promise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getProducts(owner_id, ids, filter_id, cursor, limit, sort_by, sort_direction, custom_fields, ); + async getProducts(owner_id?: number, ids?: string, filter_id?: number, cursor?: string, limit?: number, sort_by?: 'id' | 'name' | 'add_time' | 'update_time', sort_direction?: 'asc' | 'desc', updated_since?: string, custom_fields?: string, ): Promise<(axios?: AxiosInstance, basePath?: string) => Promise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getProducts(owner_id, ids, filter_id, cursor, limit, sort_by, sort_direction, updated_since, custom_fields, ); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -1387,7 +1393,7 @@ export const ProductsApiFactory = function (configuration?: Configuration, baseP * @throws {RequiredError} */ getProducts(requestParameters: ProductsApiGetProductsRequest = {}, ): Promise { - return localVarFp.getProducts(requestParameters.owner_id, requestParameters.ids, requestParameters.filter_id, requestParameters.cursor, requestParameters.limit, requestParameters.sort_by, requestParameters.sort_direction, requestParameters.custom_fields, ).then((request) => request(axios, basePath)); + return localVarFp.getProducts(requestParameters.owner_id, requestParameters.ids, requestParameters.filter_id, requestParameters.cursor, requestParameters.limit, requestParameters.sort_by, requestParameters.sort_direction, requestParameters.updated_since, requestParameters.custom_fields, ).then((request) => request(axios, basePath)); }, /** * Searches all products by name, code and/or custom fields. This endpoint is a wrapper of /v1/itemSearch with a narrower OAuth scope. @@ -1749,6 +1755,13 @@ export interface ProductsApiGetProductsRequest { */ readonly sort_direction?: 'asc' | 'desc' + /** + * If set, only products with an `update_time` later than or equal to this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z. + * @type {string} + * @memberof ProductsApiGetProducts + */ + readonly updated_since?: string + /** * Comma separated string array of custom fields keys to include. If you are only interested in a particular set of custom fields, please use this parameter for a smaller response.<br/>A maximum of 15 keys is allowed. * @type {string} @@ -2069,7 +2082,7 @@ export class ProductsApi extends BaseAPI { * @memberof ProductsApi */ public getProducts(requestParameters: ProductsApiGetProductsRequest = {}, ) { - return ProductsApiFp(this.configuration).getProducts(requestParameters.owner_id, requestParameters.ids, requestParameters.filter_id, requestParameters.cursor, requestParameters.limit, requestParameters.sort_by, requestParameters.sort_direction, requestParameters.custom_fields, ).then((request) => request(this.axios, this.basePath)); + return ProductsApiFp(this.configuration).getProducts(requestParameters.owner_id, requestParameters.ids, requestParameters.filter_id, requestParameters.cursor, requestParameters.limit, requestParameters.sort_by, requestParameters.sort_direction, requestParameters.updated_since, requestParameters.custom_fields, ).then((request) => request(this.axios, this.basePath)); } /** diff --git a/src/versions/v2/models/base-product-all-of.ts b/src/versions/v2/models/base-product-all-of.ts index 005d5d2a..40944dc4 100644 --- a/src/versions/v2/models/base-product-all-of.ts +++ b/src/versions/v2/models/base-product-all-of.ts @@ -61,11 +61,31 @@ export interface BaseProductAllOf { */ 'visible_to'?: BaseProductAllOfVisibleToConst; /** - * Information about the Pipedrive user who owns the product + * The ID of the Pipedrive user who owns the product * @type {number} */ 'owner_id'?: number; /** + * The date and time when the product was added + * @type {string} + */ + 'add_time'?: string; + /** + * The date and time when the product was last updated + * @type {string} + */ + 'update_time'?: string; + /** + * The description of the product + * @type {string} + */ + 'description'?: string; + /** + * The category of the product + * @type {string} + */ + 'category'?: string | null; + /** * An object where each key represents a custom field. All custom fields are referenced as randomly generated 40-character hashes. To clear a custom field value, set it to `null`. For multi-option fields (field type `set`), use `null` to clear the selection — sending an empty array `[]` is not supported and will result in a validation error. * @type {{ [key: string]: any | undefined; }} */ diff --git a/src/versions/v2/models/get-product-response.ts b/src/versions/v2/models/get-product-response.ts index 7695b678..63382994 100644 --- a/src/versions/v2/models/get-product-response.ts +++ b/src/versions/v2/models/get-product-response.ts @@ -15,7 +15,7 @@ // May contain unused imports in some cases // @ts-ignore -import { GetProductResponseData } from './get-product-response-data'; +import { GetProductsResponseDataInner } from './get-products-response-data-inner'; /** * @@ -30,8 +30,8 @@ export interface GetProductResponse { 'success'?: boolean; /** * - * @type {GetProductResponseData} + * @type {GetProductsResponseDataInner} */ - 'data'?: GetProductResponseData; + 'data'?: GetProductsResponseDataInner; } diff --git a/src/versions/v2/models/get-product-response-data.ts b/src/versions/v2/models/get-products-response-data-inner.ts similarity index 72% rename from src/versions/v2/models/get-product-response-data.ts rename to src/versions/v2/models/get-products-response-data-inner.ts index b644dce4..27cd2c09 100644 --- a/src/versions/v2/models/get-product-response-data.ts +++ b/src/versions/v2/models/get-products-response-data-inner.ts @@ -19,11 +19,14 @@ import { BaseProduct } from './base-product'; // May contain unused imports in some cases // @ts-ignore import { PricesArray } from './prices-array'; +// May contain unused imports in some cases +// @ts-ignore +import { PricesArrayPricesInner } from './prices-array-prices-inner'; /** - * @type GetProductResponseData + * @type GetProductsResponseDataInner * @export */ -export type GetProductResponseData = BaseProduct & PricesArray; +export type GetProductsResponseDataInner = BaseProduct & PricesArray; diff --git a/src/versions/v2/models/get-products-response.ts b/src/versions/v2/models/get-products-response.ts index 9c6fb04d..9c778f95 100644 --- a/src/versions/v2/models/get-products-response.ts +++ b/src/versions/v2/models/get-products-response.ts @@ -18,7 +18,7 @@ import { GetDealsProductsResponseAdditionalData } from './get-deals-products-response-additional-data'; // May contain unused imports in some cases // @ts-ignore -import { GetProductResponse } from './get-product-response'; +import { GetProductsResponseDataInner } from './get-products-response-data-inner'; /** * @@ -33,9 +33,9 @@ export interface GetProductsResponse { 'success'?: boolean; /** * Array containing data for all products - * @type {Array} + * @type {Array} */ - 'data'?: Array; + 'data'?: Array; /** * * @type {GetDealsProductsResponseAdditionalData} diff --git a/src/versions/v2/models/index.ts b/src/versions/v2/models/index.ts index 6691172d..779c1893 100644 --- a/src/versions/v2/models/index.ts +++ b/src/versions/v2/models/index.ts @@ -205,7 +205,6 @@ export * from './get-pipelines-response-all-of-data-inner'; export * from './get-product-image-response'; export * from './get-product-image-response-data'; export * from './get-product-response'; -export * from './get-product-response-data'; export * from './get-product-search-response'; export * from './get-product-search-response-all-of'; export * from './get-product-search-response-all-of-data'; @@ -216,6 +215,7 @@ export * from './get-product-variation-response'; export * from './get-product-variations-response'; export * from './get-product-variations-response-data-inner'; export * from './get-products-response'; +export * from './get-products-response-data-inner'; export * from './get-project-boards-response'; export * from './get-project-boards-response-data-inner'; export * from './get-project-changelog-response'; @@ -256,6 +256,7 @@ export * from './person'; export * from './person-im-inner'; export * from './person-postal-address'; export * from './prices-array'; +export * from './prices-array-prices-inner'; export * from './product-request'; export * from './project'; export * from './project-template'; diff --git a/src/versions/v2/models/prices-array-prices-inner.ts b/src/versions/v2/models/prices-array-prices-inner.ts new file mode 100644 index 00000000..517e216e --- /dev/null +++ b/src/versions/v2/models/prices-array-prices-inner.ts @@ -0,0 +1,54 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Pipedrive API v2 + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** +* +* @export +* @interface PricesArrayPricesInner +*/ +export interface PricesArrayPricesInner { + /** + * The ID of the product + * @type {number} + */ + 'product_id'?: number; + /** + * The price of the product + * @type {number} + */ + 'price'?: number; + /** + * The currency of the price + * @type {string} + */ + 'currency'?: string; + /** + * The cost of the product + * @type {number} + */ + 'cost'?: number; + /** + * The direct cost of the product + * @type {number} + */ + 'direct_cost'?: number | null; + /** + * The notes about the price + * @type {string} + */ + 'notes'?: string; +} + diff --git a/src/versions/v2/models/prices-array.ts b/src/versions/v2/models/prices-array.ts index b5456a0d..1ff09091 100644 --- a/src/versions/v2/models/prices-array.ts +++ b/src/versions/v2/models/prices-array.ts @@ -13,6 +13,9 @@ */ +// May contain unused imports in some cases +// @ts-ignore +import { PricesArrayPricesInner } from './prices-array-prices-inner'; /** * @@ -21,9 +24,9 @@ */ export interface PricesArray { /** - * Array of objects, each containing: product_id (number), currency (string), price (number), cost (number), direct_cost (number | null), notes (string) - * @type {Array} + * The prices of the product in different currencies + * @type {Array} */ - 'prices'?: Array; + 'prices'?: Array; } diff --git a/src/versions/v2/models/update-product-response.ts b/src/versions/v2/models/update-product-response.ts index f17b03e5..2ed4ac43 100644 --- a/src/versions/v2/models/update-product-response.ts +++ b/src/versions/v2/models/update-product-response.ts @@ -15,7 +15,7 @@ // May contain unused imports in some cases // @ts-ignore -import { GetProductResponseData } from './get-product-response-data'; +import { GetProductsResponseDataInner } from './get-products-response-data-inner'; /** * @@ -30,8 +30,8 @@ export interface UpdateProductResponse { 'success'?: boolean; /** * - * @type {GetProductResponseData} + * @type {GetProductsResponseDataInner} */ - 'data'?: GetProductResponseData; + 'data'?: GetProductsResponseDataInner; }