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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 18 additions & 5 deletions src/versions/v2/api/products-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<RequestArgs> => {
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<RequestArgs> => {
const localVarPath = `/products`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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: &#x60;id&#x60;, &#x60;name&#x60;, &#x60;add_time&#x60;, &#x60;update_time&#x60;.
* @param {'asc' | 'desc'} [sort_direction] The sorting direction. Supported values: &#x60;asc&#x60;, &#x60;desc&#x60;.
* @param {string} [updated_since] If set, only products with an &#x60;update_time&#x60; 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.&lt;br/&gt;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<GetProductsResponse>> {
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<GetProductsResponse>> {
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);
},
/**
Expand Down Expand Up @@ -1387,7 +1393,7 @@ export const ProductsApiFactory = function (configuration?: Configuration, baseP
* @throws {RequiredError}
*/
getProducts(requestParameters: ProductsApiGetProductsRequest = {}, ): Promise<GetProductsResponse> {
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 <a href=\"https://developers.pipedrive.com/docs/api/v1/ItemSearch#searchItem\">/v1/itemSearch</a> with a narrower OAuth scope.
Expand Down Expand Up @@ -1749,6 +1755,13 @@ export interface ProductsApiGetProductsRequest {
*/
readonly sort_direction?: 'asc' | 'desc'

/**
* If set, only products with an &#x60;update_time&#x60; 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.&lt;br/&gt;A maximum of 15 keys is allowed.
* @type {string}
Expand Down Expand Up @@ -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));
}

/**
Expand Down
22 changes: 21 additions & 1 deletion src/versions/v2/models/base-product-all-of.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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; }}
*/
Expand Down
6 changes: 3 additions & 3 deletions src/versions/v2/models/get-product-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

/**
*
Expand All @@ -30,8 +30,8 @@ export interface GetProductResponse {
'success'?: boolean;
/**
*
* @type {GetProductResponseData}
* @type {GetProductsResponseDataInner}
*/
'data'?: GetProductResponseData;
'data'?: GetProductsResponseDataInner;
}

Original file line number Diff line number Diff line change
Expand Up @@ -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;


6 changes: 3 additions & 3 deletions src/versions/v2/models/get-products-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

/**
*
Expand All @@ -33,9 +33,9 @@ export interface GetProductsResponse {
'success'?: boolean;
/**
* Array containing data for all products
* @type {Array<GetProductResponse>}
* @type {Array<GetProductsResponseDataInner>}
*/
'data'?: Array<GetProductResponse>;
'data'?: Array<GetProductsResponseDataInner>;
/**
*
* @type {GetDealsProductsResponseAdditionalData}
Expand Down
3 changes: 2 additions & 1 deletion src/versions/v2/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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';
Expand Down Expand Up @@ -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';
Expand Down
54 changes: 54 additions & 0 deletions src/versions/v2/models/prices-array-prices-inner.ts
Original file line number Diff line number Diff line change
@@ -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;
}

9 changes: 6 additions & 3 deletions src/versions/v2/models/prices-array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
*/


// May contain unused imports in some cases
// @ts-ignore
import { PricesArrayPricesInner } from './prices-array-prices-inner';

/**
*
Expand All @@ -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<object>}
* The prices of the product in different currencies
* @type {Array<PricesArrayPricesInner>}
*/
'prices'?: Array<object>;
'prices'?: Array<PricesArrayPricesInner>;
}

6 changes: 3 additions & 3 deletions src/versions/v2/models/update-product-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

/**
*
Expand All @@ -30,8 +30,8 @@ export interface UpdateProductResponse {
'success'?: boolean;
/**
*
* @type {GetProductResponseData}
* @type {GetProductsResponseDataInner}
*/
'data'?: GetProductResponseData;
'data'?: GetProductsResponseDataInner;
}