@lonca/trendyol 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.cjs +1031 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1049 -1
- package/dist/index.d.ts +1049 -1
- package/dist/index.js +1028 -4
- package/dist/index.js.map +1 -1
- package/package.json +11 -11
package/dist/index.d.cts
CHANGED
|
@@ -77,6 +77,1049 @@ declare class BrandsResource {
|
|
|
77
77
|
* ```
|
|
78
78
|
*/
|
|
79
79
|
list(params?: CursorPaginationParams): Promise<CursorPage<Brand>>;
|
|
80
|
+
/**
|
|
81
|
+
* Search brands by name. Useful when you need a brand's numeric ID for
|
|
82
|
+
* `createProducts` and don't want to page through the full `list()`
|
|
83
|
+
* (1000 brands per page).
|
|
84
|
+
*
|
|
85
|
+
* **Discovery-first wire fact (verified STAGE 2026-05-25):** Trendyol's
|
|
86
|
+
* doc claims this is a case-sensitive *exact* match, but live behaviour
|
|
87
|
+
* is **substring + case-insensitive** — `search('Trendyol')` returns
|
|
88
|
+
* 17 hits including `TRENDYOLMILLA`, `trendyol vavist`, `Trendyol Üyelik`.
|
|
89
|
+
* Plan for ranking your results client-side if you need an exact match.
|
|
90
|
+
* The endpoint returns an empty array when nothing matches (no 404).
|
|
91
|
+
*
|
|
92
|
+
* @param name The brand name to search for.
|
|
93
|
+
*/
|
|
94
|
+
search(name: string): Promise<Brand[]>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* A node in the Trendyol category tree.
|
|
99
|
+
*
|
|
100
|
+
* Trendyol exposes categories as a deeply nested structure where each node
|
|
101
|
+
* can have child categories under `subCategories`. We normalize numeric IDs
|
|
102
|
+
* to strings to match the `@lonca/core` convention.
|
|
103
|
+
*/
|
|
104
|
+
interface Category {
|
|
105
|
+
id: string;
|
|
106
|
+
name: string;
|
|
107
|
+
/** `null` when this is a root category. */
|
|
108
|
+
parentId: string | null;
|
|
109
|
+
subCategories: Category[];
|
|
110
|
+
}
|
|
111
|
+
/** A single allowed value for a category attribute. */
|
|
112
|
+
interface CategoryAttributeValue {
|
|
113
|
+
id: string;
|
|
114
|
+
name: string;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Result of `categories.getByBarcodes` — a barcode → category mapping
|
|
118
|
+
* sourced from Trendyol's Export Center (AutoFT) lookup endpoint.
|
|
119
|
+
*/
|
|
120
|
+
interface BarcodeCategoryLookup {
|
|
121
|
+
/** Successful matches. */
|
|
122
|
+
matches: Array<{
|
|
123
|
+
barcode: string;
|
|
124
|
+
category: {
|
|
125
|
+
id: string;
|
|
126
|
+
name: string;
|
|
127
|
+
};
|
|
128
|
+
}>;
|
|
129
|
+
/** Barcodes Trendyol could not resolve to a category. */
|
|
130
|
+
notFound: string[];
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* A required or optional attribute for products in a given category.
|
|
134
|
+
* Use these when constructing a `createProduct V2` payload — the API rejects
|
|
135
|
+
* products that omit `required` attributes.
|
|
136
|
+
*/
|
|
137
|
+
interface CategoryAttribute {
|
|
138
|
+
id: string;
|
|
139
|
+
name: string;
|
|
140
|
+
/** The category this attribute belongs to (echoed back by Trendyol). */
|
|
141
|
+
categoryId?: string;
|
|
142
|
+
required: boolean;
|
|
143
|
+
/** Whether the attribute accepts custom text values in addition to the listed ones. */
|
|
144
|
+
allowCustom: boolean;
|
|
145
|
+
/** Whether the attribute participates in product variants (e.g. color, size). */
|
|
146
|
+
varianter: boolean;
|
|
147
|
+
/** Whether the attribute is used as a price slicer (e.g. size for shoes). */
|
|
148
|
+
slicer: boolean;
|
|
149
|
+
/**
|
|
150
|
+
* V2-only: whether the attribute accepts multiple values at once.
|
|
151
|
+
* Present on responses from the V2 `getCategoryAttributes` endpoint; absent on V1.
|
|
152
|
+
*/
|
|
153
|
+
allowMultipleAttributeValues?: boolean;
|
|
154
|
+
/**
|
|
155
|
+
* Allowed values for this attribute.
|
|
156
|
+
*
|
|
157
|
+
* NOTE: Trendyol's live API often omits this field on the `getCategoryAttributes`
|
|
158
|
+
* response — the endpoint returns attribute metadata + flags, not the full value
|
|
159
|
+
* catalog. In that case `values` is an empty array. If `allowCustom` is `true`,
|
|
160
|
+
* any custom text is accepted; otherwise use `client.categories.getAttributeValues(categoryId, attributeId)`
|
|
161
|
+
* to fetch the catalog from the dedicated V2 endpoint.
|
|
162
|
+
*/
|
|
163
|
+
values: CategoryAttributeValue[];
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
type ListCategoryAttributeValuesParams = CursorPaginationParams;
|
|
167
|
+
/**
|
|
168
|
+
* Trendyol category-tree and category-attribute endpoints.
|
|
169
|
+
*
|
|
170
|
+
* Rate limits (per Trendyol service limits):
|
|
171
|
+
* - Category list: 50 req/min
|
|
172
|
+
* - Category attributes: 50 req/min
|
|
173
|
+
* - Category attribute values: 50 req/min (same service tier)
|
|
174
|
+
*
|
|
175
|
+
* All three counters live on the same Trendyol service, so we share one
|
|
176
|
+
* limiter across the endpoints.
|
|
177
|
+
*/
|
|
178
|
+
declare class CategoriesResource {
|
|
179
|
+
private readonly transport;
|
|
180
|
+
/**
|
|
181
|
+
* Trendyol seller (supplier) ID — required only for the AutoFT-scoped
|
|
182
|
+
* `getByBarcodes` lookup. Other category endpoints don't need it.
|
|
183
|
+
* Provided automatically when constructed via `createTrendyolClient`.
|
|
184
|
+
*/
|
|
185
|
+
private readonly sellerId?;
|
|
186
|
+
private readonly limiter;
|
|
187
|
+
constructor(transport: TrendyolTransport, limiter?: TokenBucketRateLimiter,
|
|
188
|
+
/**
|
|
189
|
+
* Trendyol seller (supplier) ID — required only for the AutoFT-scoped
|
|
190
|
+
* `getByBarcodes` lookup. Other category endpoints don't need it.
|
|
191
|
+
* Provided automatically when constructed via `createTrendyolClient`.
|
|
192
|
+
*/
|
|
193
|
+
sellerId?: number | undefined);
|
|
194
|
+
/**
|
|
195
|
+
* Fetch the full Trendyol category tree.
|
|
196
|
+
*
|
|
197
|
+
* Trendyol returns the entire tree in one response — there is no pagination.
|
|
198
|
+
* Cache the result aggressively in your application; the tree changes rarely.
|
|
199
|
+
*/
|
|
200
|
+
list(): Promise<Category[]>;
|
|
201
|
+
/**
|
|
202
|
+
* Fetch the attributes (required and optional) for a single category.
|
|
203
|
+
*
|
|
204
|
+
* Call this before `createProduct V2` so you know which attributes are
|
|
205
|
+
* mandatory — the API rejects products that omit any `required` attribute.
|
|
206
|
+
*
|
|
207
|
+
* @param categoryId Trendyol numeric category ID; accepts `string` or `number`.
|
|
208
|
+
*/
|
|
209
|
+
getAttributes(categoryId: string | number): Promise<CategoryAttribute[]>;
|
|
210
|
+
/**
|
|
211
|
+
* Fetch the allowed values for a single category attribute (paginated).
|
|
212
|
+
*
|
|
213
|
+
* `getCategoryAttributes` returns attribute metadata + flags but typically
|
|
214
|
+
* omits the value catalog. Use this method to fetch the catalog for an
|
|
215
|
+
* attribute when `allowCustom` is `false` and you need to map your data
|
|
216
|
+
* onto Trendyol's accepted values.
|
|
217
|
+
*
|
|
218
|
+
* @param categoryId Trendyol numeric category ID; accepts `string` or `number`.
|
|
219
|
+
* @param attributeId Attribute ID returned by `getAttributes`.
|
|
220
|
+
* @param params Cursor pagination (max page size 1000; default 100).
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```ts
|
|
224
|
+
* import { paginate } from '@lonca/core';
|
|
225
|
+
* for await (const value of paginate((p) =>
|
|
226
|
+
* client.categories.getAttributeValues(catId, attrId, p),
|
|
227
|
+
* )) {
|
|
228
|
+
* console.log(value.id, value.name);
|
|
229
|
+
* }
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
getAttributeValues(categoryId: string | number, attributeId: string | number, params?: ListCategoryAttributeValuesParams): Promise<CursorPage<CategoryAttributeValue>>;
|
|
233
|
+
/**
|
|
234
|
+
* Look up category info for a list of barcodes (Trendyol Export Center
|
|
235
|
+
* / AutoFT endpoint).
|
|
236
|
+
*
|
|
237
|
+
* **Requires Export Center enrollment.** Sellers who have not joined
|
|
238
|
+
* Trendyol's "İhracat Merkezi" program will get an auth error on this
|
|
239
|
+
* endpoint even though their regular Marketplace credentials are valid.
|
|
240
|
+
*
|
|
241
|
+
* @param barcodes 1–N barcodes to look up.
|
|
242
|
+
* @throws {ValidationError} when `barcodes` is empty.
|
|
243
|
+
* @throws Error when the client was created without a `sellerId` and this
|
|
244
|
+
* method is called directly (use `createTrendyolClient` to wire it).
|
|
245
|
+
*/
|
|
246
|
+
getByBarcodes(barcodes: string[]): Promise<BarcodeCategoryLookup>;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* A single price / stock update entry.
|
|
251
|
+
*
|
|
252
|
+
* `barcode` is the only required field. Include any combination of:
|
|
253
|
+
* - `quantity` to update stock (max 20 000 per product)
|
|
254
|
+
* - `salePrice` to update the sale price
|
|
255
|
+
* - `listPrice` to update the list (strikethrough) price
|
|
256
|
+
*
|
|
257
|
+
* `listPrice` must be greater than or equal to `salePrice`.
|
|
258
|
+
*/
|
|
259
|
+
interface PriceInventoryUpdate {
|
|
260
|
+
barcode: string;
|
|
261
|
+
quantity?: number;
|
|
262
|
+
salePrice?: number;
|
|
263
|
+
listPrice?: number;
|
|
264
|
+
}
|
|
265
|
+
/** Response from `updatePriceAndInventory` — poll with `products.getBatchStatus`. */
|
|
266
|
+
interface UpdatePriceInventoryResponse {
|
|
267
|
+
batchRequestId: string;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Trendyol stock & price update endpoint (a.k.a. `updatePriceAndInventory`).
|
|
272
|
+
*
|
|
273
|
+
* Rate limit: **none** — Trendyol explicitly lists this endpoint as
|
|
274
|
+
* `NO LIMIT` in its service limits table. The `15-minute duplicate
|
|
275
|
+
* suppression` rule still applies on Trendyol's side, but that's a
|
|
276
|
+
* server-side concern.
|
|
277
|
+
*
|
|
278
|
+
* The endpoint is asynchronous. The response carries a `batchRequestId`
|
|
279
|
+
* you can poll with `client.products.getBatchStatus(batchRequestId)` —
|
|
280
|
+
* Trendyol retains the result for 4 hours.
|
|
281
|
+
*/
|
|
282
|
+
declare class InventoryResource {
|
|
283
|
+
private readonly transport;
|
|
284
|
+
private readonly sellerId;
|
|
285
|
+
constructor(transport: TrendyolTransport, sellerId: number);
|
|
286
|
+
/**
|
|
287
|
+
* Update price and/or stock for one or more SKUs (by barcode).
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* ```ts
|
|
291
|
+
* const { batchRequestId } = await client.inventory.update([
|
|
292
|
+
* { barcode: 'ABC123', quantity: 42, salePrice: 199.9, listPrice: 249.9 },
|
|
293
|
+
* { barcode: 'XYZ789', quantity: 0 },
|
|
294
|
+
* ]);
|
|
295
|
+
* const status = await client.products.getBatchStatus(batchRequestId);
|
|
296
|
+
* ```
|
|
297
|
+
*
|
|
298
|
+
* @throws {ValidationError} when `items` is empty or longer than 1000.
|
|
299
|
+
*/
|
|
300
|
+
update(items: PriceInventoryUpdate[]): Promise<UpdatePriceInventoryResponse>;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Trendyol shipment-package status.
|
|
305
|
+
*
|
|
306
|
+
* Trendyol uses ~13 distinct values (Created, Picking, Invoiced, Shipped,
|
|
307
|
+
* Cancelled, Delivered, UnDelivered, Returned, UnSupplied, Awaiting,
|
|
308
|
+
* UnPacked, AtCollectionPoint, Verified). Typed as a union with an open
|
|
309
|
+
* escape so unknown values still type-check.
|
|
310
|
+
*/
|
|
311
|
+
type ShipmentPackageStatus = 'Created' | 'Picking' | 'Invoiced' | 'Shipped' | 'Cancelled' | 'Delivered' | 'UnDelivered' | 'Returned' | 'UnSupplied' | 'Awaiting' | 'UnPacked' | 'AtCollectionPoint' | 'Verified' | (string & {});
|
|
312
|
+
interface OrderAddressLines {
|
|
313
|
+
addressLine1?: string;
|
|
314
|
+
addressLine2?: string;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* A customer or invoice/shipment address returned alongside a shipment package.
|
|
318
|
+
* Field set is conservative — Trendyol returns many optional locality fields
|
|
319
|
+
* and we surface them as-is.
|
|
320
|
+
*/
|
|
321
|
+
interface OrderAddress {
|
|
322
|
+
id?: string;
|
|
323
|
+
firstName?: string;
|
|
324
|
+
lastName?: string;
|
|
325
|
+
fullName?: string;
|
|
326
|
+
company?: string;
|
|
327
|
+
address1?: string;
|
|
328
|
+
address2?: string;
|
|
329
|
+
fullAddress?: string;
|
|
330
|
+
shortAddress?: string;
|
|
331
|
+
city?: string;
|
|
332
|
+
cityCode?: number;
|
|
333
|
+
district?: string;
|
|
334
|
+
districtId?: number;
|
|
335
|
+
neighborhoodId?: number;
|
|
336
|
+
countyId?: number;
|
|
337
|
+
countyName?: string;
|
|
338
|
+
stateName?: string;
|
|
339
|
+
postalCode?: string;
|
|
340
|
+
countryCode?: string;
|
|
341
|
+
phone?: string;
|
|
342
|
+
addressLines?: OrderAddressLines;
|
|
343
|
+
}
|
|
344
|
+
/** Customer details on a shipment package (a subset of what Trendyol exposes). */
|
|
345
|
+
interface OrderCustomer {
|
|
346
|
+
id?: string;
|
|
347
|
+
firstName: string;
|
|
348
|
+
lastName: string;
|
|
349
|
+
email?: string;
|
|
350
|
+
taxNumber?: string;
|
|
351
|
+
identityNumber?: string;
|
|
352
|
+
}
|
|
353
|
+
interface OrderLineDiscountDetail {
|
|
354
|
+
lineItemPrice?: number;
|
|
355
|
+
lineItemSellerDiscount?: number;
|
|
356
|
+
lineItemTyDiscount?: number;
|
|
357
|
+
}
|
|
358
|
+
/** A single item line inside a shipment package. */
|
|
359
|
+
interface OrderLine {
|
|
360
|
+
/** Trendyol's `lineId`. */
|
|
361
|
+
id: string;
|
|
362
|
+
quantity: number;
|
|
363
|
+
productName: string;
|
|
364
|
+
barcode: string;
|
|
365
|
+
productSize?: string;
|
|
366
|
+
productColor?: string;
|
|
367
|
+
stockCode?: string;
|
|
368
|
+
contentId?: string;
|
|
369
|
+
sellerId?: string;
|
|
370
|
+
productCategoryId?: string;
|
|
371
|
+
salesCampaignId?: string;
|
|
372
|
+
currencyCode?: string;
|
|
373
|
+
lineUnitPrice: number;
|
|
374
|
+
lineGrossAmount: number;
|
|
375
|
+
lineSellerDiscount?: number;
|
|
376
|
+
lineTyDiscount?: number;
|
|
377
|
+
lineTotalDiscount?: number;
|
|
378
|
+
vatRate?: number;
|
|
379
|
+
commission?: number;
|
|
380
|
+
orderLineItemStatusName?: string;
|
|
381
|
+
businessUnit?: string;
|
|
382
|
+
fastDeliveryOptions?: unknown[];
|
|
383
|
+
discountDetails?: OrderLineDiscountDetail[];
|
|
384
|
+
/** Untouched raw line response. */
|
|
385
|
+
raw: Record<string, unknown>;
|
|
386
|
+
}
|
|
387
|
+
/** A status transition entry in `packageHistories`. */
|
|
388
|
+
interface PackageHistoryEntry {
|
|
389
|
+
status?: ShipmentPackageStatus;
|
|
390
|
+
/** ISO 8601 UTC string (converted from Trendyol's ms-epoch). */
|
|
391
|
+
createdAt?: string;
|
|
392
|
+
raw: Record<string, unknown>;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* A Trendyol order — Trendyol models orders as "shipment packages". A single
|
|
396
|
+
* customer order may produce multiple shipment packages (one per warehouse,
|
|
397
|
+
* one per cancellation, etc.).
|
|
398
|
+
*
|
|
399
|
+
* `id` is the `shipmentPackageId` (the operational unit); `orderNumber`
|
|
400
|
+
* groups packages that came from the same customer order.
|
|
401
|
+
*/
|
|
402
|
+
interface ShipmentPackage {
|
|
403
|
+
/** `shipmentPackageId` — the operational identifier for this package. */
|
|
404
|
+
id: string;
|
|
405
|
+
orderNumber: string;
|
|
406
|
+
shipmentNumber?: string;
|
|
407
|
+
originPackageIds?: string[] | null;
|
|
408
|
+
warehouseId?: string;
|
|
409
|
+
supplierId?: string;
|
|
410
|
+
status: ShipmentPackageStatus;
|
|
411
|
+
/** Usually identical to `status`; surfaced for completeness. */
|
|
412
|
+
shipmentPackageStatus?: ShipmentPackageStatus;
|
|
413
|
+
customer: OrderCustomer;
|
|
414
|
+
orderDate: string;
|
|
415
|
+
lastModifiedDate: string;
|
|
416
|
+
agreedDeliveryDate?: string;
|
|
417
|
+
estimatedDeliveryStartDate?: string;
|
|
418
|
+
estimatedDeliveryEndDate?: string;
|
|
419
|
+
originShipmentDate?: string;
|
|
420
|
+
currencyCode: string;
|
|
421
|
+
packageTotalPrice: number;
|
|
422
|
+
packageGrossAmount: number;
|
|
423
|
+
packageSellerDiscount: number;
|
|
424
|
+
packageTyDiscount: number;
|
|
425
|
+
packageTotalDiscount: number;
|
|
426
|
+
invoiceAddress?: OrderAddress;
|
|
427
|
+
shipmentAddress?: OrderAddress;
|
|
428
|
+
deliveryAddressType?: string;
|
|
429
|
+
cargoTrackingNumber?: string;
|
|
430
|
+
cargoProviderName?: string;
|
|
431
|
+
cargoProviderId?: string;
|
|
432
|
+
cargoSenderNumber?: string;
|
|
433
|
+
deliveryType?: string;
|
|
434
|
+
whoPays?: number;
|
|
435
|
+
timeSlotId?: number;
|
|
436
|
+
fastDelivery?: boolean;
|
|
437
|
+
fastDeliveryType?: string;
|
|
438
|
+
deliveredByService?: boolean;
|
|
439
|
+
commercial?: boolean;
|
|
440
|
+
micro?: boolean;
|
|
441
|
+
giftBoxRequested?: boolean;
|
|
442
|
+
/** Renamed from Trendyol's wire field `3pByTrendyol` (identifier cannot start with a digit). */
|
|
443
|
+
threePByTrendyol?: boolean;
|
|
444
|
+
containsDangerousProduct?: boolean;
|
|
445
|
+
isCod?: boolean;
|
|
446
|
+
is4P?: boolean;
|
|
447
|
+
invoiceLink?: string;
|
|
448
|
+
createdBy?: string;
|
|
449
|
+
lines: OrderLine[];
|
|
450
|
+
packageHistories: PackageHistoryEntry[];
|
|
451
|
+
/** Untouched raw response for fields not modeled yet. */
|
|
452
|
+
raw: Record<string, unknown>;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
interface ListOrdersParams extends CursorPaginationParams {
|
|
456
|
+
status?: ShipmentPackageStatus;
|
|
457
|
+
orderNumber?: string;
|
|
458
|
+
/** Filter packages updated on or after this date (Trendyol expects ms-epoch). */
|
|
459
|
+
startDate?: Date;
|
|
460
|
+
/** Filter packages updated on or before this date. */
|
|
461
|
+
endDate?: Date;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Trendyol order (shipment-package) endpoints.
|
|
465
|
+
*
|
|
466
|
+
* Rate limit (per Trendyol service limits): scheduled to tighten on 2026-05-15;
|
|
467
|
+
* for now we set a generous default that the user can tune via the constructor.
|
|
468
|
+
*
|
|
469
|
+
* Pagination: Trendyol uses page-based pagination here (not nextPageToken).
|
|
470
|
+
* The SDK still exposes `CursorPage<ShipmentPackage>` so the caller can
|
|
471
|
+
* iterate with `paginate()` from `@lonca/core`; the opaque cursor encodes the
|
|
472
|
+
* page index.
|
|
473
|
+
*/
|
|
474
|
+
declare class OrdersResource {
|
|
475
|
+
private readonly transport;
|
|
476
|
+
private readonly sellerId;
|
|
477
|
+
private readonly limiter;
|
|
478
|
+
constructor(transport: TrendyolTransport, sellerId: number, limiter?: TokenBucketRateLimiter);
|
|
479
|
+
/**
|
|
480
|
+
* List shipment packages for the seller.
|
|
481
|
+
*
|
|
482
|
+
* @example
|
|
483
|
+
* ```ts
|
|
484
|
+
* import { paginate } from '@lonca/core';
|
|
485
|
+
* for await (const pkg of paginate((p) => client.orders.list({ ...p, status: 'Created' }))) {
|
|
486
|
+
* console.log(pkg.id, pkg.status, pkg.customer.firstName);
|
|
487
|
+
* }
|
|
488
|
+
* ```
|
|
489
|
+
*/
|
|
490
|
+
list(params?: ListOrdersParams): Promise<CursorPage<ShipmentPackage>>;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/** A `{ id, name }` reference object used in product/category/brand wire types. */
|
|
494
|
+
interface NamedRef {
|
|
495
|
+
id: string;
|
|
496
|
+
name: string;
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* A single attribute on a Trendyol product or variant.
|
|
500
|
+
*
|
|
501
|
+
* `attributeValueId` and `attributeValue` are mutually exclusive in createProduct
|
|
502
|
+
* payloads but can both be present in filter responses.
|
|
503
|
+
*/
|
|
504
|
+
interface ProductAttribute {
|
|
505
|
+
attributeId: string;
|
|
506
|
+
attributeName?: string;
|
|
507
|
+
attributeValueId?: string;
|
|
508
|
+
attributeValue?: string;
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* A variant of a Trendyol product — the actual purchasable SKU.
|
|
512
|
+
*
|
|
513
|
+
* Trendyol scopes barcode + stock + commission to the variant level even for
|
|
514
|
+
* products that only have a single variant. To read a product's barcode use
|
|
515
|
+
* `product.variants[0].barcode`.
|
|
516
|
+
*/
|
|
517
|
+
interface ProductVariant {
|
|
518
|
+
variantId: string;
|
|
519
|
+
barcode: string;
|
|
520
|
+
commission?: number;
|
|
521
|
+
attributes: ProductAttribute[];
|
|
522
|
+
productUrl?: string;
|
|
523
|
+
onSale?: boolean;
|
|
524
|
+
/** Stock quantity (when the response includes stock data). */
|
|
525
|
+
stock?: number;
|
|
526
|
+
/** Untouched raw response for fields not modeled yet. */
|
|
527
|
+
raw: Record<string, unknown>;
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* A Trendyol marketplace product (approved variant).
|
|
531
|
+
*
|
|
532
|
+
* Lonca surfaces the stable fields we have verified against live Trendyol
|
|
533
|
+
* responses. Everything else stays accessible via `raw`.
|
|
534
|
+
*/
|
|
535
|
+
interface Product {
|
|
536
|
+
contentId: string;
|
|
537
|
+
productMainId: string;
|
|
538
|
+
title: string;
|
|
539
|
+
description?: string;
|
|
540
|
+
brand: NamedRef;
|
|
541
|
+
category: NamedRef;
|
|
542
|
+
/** Image URLs in display order. */
|
|
543
|
+
images: string[];
|
|
544
|
+
attributes: ProductAttribute[];
|
|
545
|
+
variants: ProductVariant[];
|
|
546
|
+
/** ISO 8601 UTC string (converted from Trendyol's ms-epoch). */
|
|
547
|
+
createdAt: string;
|
|
548
|
+
/** ISO 8601 UTC string. */
|
|
549
|
+
updatedAt: string;
|
|
550
|
+
lastModifiedBy?: string;
|
|
551
|
+
/** Untouched raw response — read fields we have not modeled yet. */
|
|
552
|
+
raw: Record<string, unknown>;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Lifecycle status of an unapproved (draft) product on Trendyol.
|
|
556
|
+
*
|
|
557
|
+
* Verified values seen on STAGE/PROD as of 2026-05-25:
|
|
558
|
+
* - `pendingApproval` — submitted; Trendyol content review in progress.
|
|
559
|
+
* - `rejected` — review failed; `rejectReasonDetails` is populated.
|
|
560
|
+
*
|
|
561
|
+
* Older docs also mention `waiting`. Treat as open-enum (`(string & {})`)
|
|
562
|
+
* since Trendyol can add new statuses without notice.
|
|
563
|
+
*/
|
|
564
|
+
type UnapprovedProductStatus = 'pendingApproval' | 'waiting' | 'rejected' | (string & {});
|
|
565
|
+
interface UnapprovedProductRejectReason {
|
|
566
|
+
/** Short title (e.g. "Kategori Bilgisi Eksik veya Yanlış"). */
|
|
567
|
+
rejectReason?: string;
|
|
568
|
+
/** Full explanation of the rejection. */
|
|
569
|
+
rejectReasonDetail?: string;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* An unapproved (draft) product as returned by `filterUnapprovedProducts`.
|
|
573
|
+
*
|
|
574
|
+
* Important: the wire shape is **flatter** than the approved-product shape
|
|
575
|
+
* exposed by `Product` — `barcode`, `quantity`, `salePrice`, etc. live at the
|
|
576
|
+
* root (no `variants[]` array). Each draft is one barcode/SKU.
|
|
577
|
+
*
|
|
578
|
+
* Verified against Trendyol STAGE on 2026-05-25. The official OpenAPI spec
|
|
579
|
+
* calls the image-list field `media`, but the live API returns it as
|
|
580
|
+
* `images`. SDK normalizes to `images`.
|
|
581
|
+
*/
|
|
582
|
+
interface UnapprovedProduct {
|
|
583
|
+
/** Seller (supplier) ID echoed back by Trendyol. */
|
|
584
|
+
supplierId?: string;
|
|
585
|
+
productMainId: string;
|
|
586
|
+
/** Lifecycle status — see `UnapprovedProductStatus`. */
|
|
587
|
+
status?: UnapprovedProductStatus;
|
|
588
|
+
brand: NamedRef;
|
|
589
|
+
category: NamedRef;
|
|
590
|
+
barcode: string;
|
|
591
|
+
title: string;
|
|
592
|
+
description?: string;
|
|
593
|
+
/** Stock quantity at the moment of the query. */
|
|
594
|
+
quantity?: number;
|
|
595
|
+
listPrice?: number;
|
|
596
|
+
salePrice?: number;
|
|
597
|
+
/** VAT rate as a percentage (e.g. `20` for 20%). */
|
|
598
|
+
vatRate?: number;
|
|
599
|
+
dimensionalWeight?: number;
|
|
600
|
+
stockCode?: string;
|
|
601
|
+
/** Image URLs in display order (Trendyol's `images` field, spec says `media`). */
|
|
602
|
+
images: string[];
|
|
603
|
+
attributes: ProductAttribute[];
|
|
604
|
+
/** Populated when `status === 'rejected'`. */
|
|
605
|
+
rejectReasonDetails: UnapprovedProductRejectReason[];
|
|
606
|
+
/** Returned by Trendyol; null when the seller has not configured this. */
|
|
607
|
+
origin?: string | null;
|
|
608
|
+
locationBasedDelivery?: 'ENABLED' | 'DISABLED' | null;
|
|
609
|
+
lotNumber?: string | null;
|
|
610
|
+
/** Special consumption tax (ÖTV) where applicable. */
|
|
611
|
+
specialConsumptionTax?: number | null;
|
|
612
|
+
/** Suggested governance retail price (Suggested Government Retail price). */
|
|
613
|
+
sgrPrice?: number | null;
|
|
614
|
+
/** ISO 8601 UTC string (from `createDateTime` ms-epoch). */
|
|
615
|
+
createdAt?: string;
|
|
616
|
+
/** ISO 8601 UTC string (from `lastUpdateDate`). */
|
|
617
|
+
updatedAt?: string;
|
|
618
|
+
/** ISO 8601 UTC string (from `lastPriceChangeDate`). */
|
|
619
|
+
lastPriceChangedAt?: string;
|
|
620
|
+
/** ISO 8601 UTC string (from `lastStockChangeDate`). */
|
|
621
|
+
lastStockChangedAt?: string;
|
|
622
|
+
/** Untouched raw response. */
|
|
623
|
+
raw: Record<string, unknown>;
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Basic lifecycle info for a single product, returned by `getProductBase`.
|
|
627
|
+
*
|
|
628
|
+
* Cheap to call (no body — just barcode in path) and useful as a polling
|
|
629
|
+
* primitive after `createProducts` to detect `approved: true`.
|
|
630
|
+
*/
|
|
631
|
+
interface ProductBase {
|
|
632
|
+
barcode: string;
|
|
633
|
+
approved: boolean;
|
|
634
|
+
archived: boolean;
|
|
635
|
+
/** ISO 8601 UTC string (from `approvedDate` ms-epoch); `undefined` until approved. */
|
|
636
|
+
approvedAt?: string;
|
|
637
|
+
/** Stable listing ID assigned after approval. */
|
|
638
|
+
listingId?: string;
|
|
639
|
+
/** Trendyol's content ID — the same field on `Product.contentId`. */
|
|
640
|
+
contentId?: string;
|
|
641
|
+
/** Untouched raw response. */
|
|
642
|
+
raw: Record<string, unknown>;
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Buybox status for a single barcode, returned by `getBuyboxInformation`.
|
|
646
|
+
*
|
|
647
|
+
* `buyboxOrder === 1` means you currently hold the buybox.
|
|
648
|
+
* `secondBuyboxPrice` / `thirdBuyboxPrice` are surfaced from live wire (not
|
|
649
|
+
* in the spec) so you can see what other sellers are charging.
|
|
650
|
+
*/
|
|
651
|
+
interface BuyboxInfo {
|
|
652
|
+
barcode: string;
|
|
653
|
+
/** Position in the buybox ranking (1 = you hold it). */
|
|
654
|
+
buyboxOrder?: number;
|
|
655
|
+
/** Current buybox-winning price. */
|
|
656
|
+
buyboxPrice?: number;
|
|
657
|
+
hasMultipleSeller?: boolean;
|
|
658
|
+
/** Second-best price (when multiple sellers compete). */
|
|
659
|
+
secondBuyboxPrice?: number | null;
|
|
660
|
+
/** Third-best price. */
|
|
661
|
+
thirdBuyboxPrice?: number | null;
|
|
662
|
+
/** Untouched raw response. */
|
|
663
|
+
raw: Record<string, unknown>;
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Status of an async batch request returned by `createProducts`,
|
|
667
|
+
* `updatePriceAndInventory`, and other Trendyol bulk endpoints.
|
|
668
|
+
*/
|
|
669
|
+
type BatchRequestStatus = 'PROCESSING' | 'COMPLETED' | 'FAILED' | (string & {});
|
|
670
|
+
interface BatchRequestItemResult {
|
|
671
|
+
requestItem?: unknown;
|
|
672
|
+
status?: string;
|
|
673
|
+
failureReasons?: string[];
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* Result of polling `getBatchRequestResult` for a previously-submitted batch.
|
|
677
|
+
*
|
|
678
|
+
* Trendyol retains batch results for **4 hours** after the originating request.
|
|
679
|
+
*/
|
|
680
|
+
interface BatchRequestResult {
|
|
681
|
+
batchRequestId: string;
|
|
682
|
+
status: BatchRequestStatus;
|
|
683
|
+
itemCount?: number;
|
|
684
|
+
failedItemCount?: number;
|
|
685
|
+
items: BatchRequestItemResult[];
|
|
686
|
+
/** ISO 8601 UTC string (converted from Trendyol's ms-epoch). */
|
|
687
|
+
createdAt?: string;
|
|
688
|
+
/** ISO 8601 UTC string. */
|
|
689
|
+
lastModifiedAt?: string;
|
|
690
|
+
/** Trendyol category of submission (e.g. `MarketPlace`). */
|
|
691
|
+
sourceType?: string;
|
|
692
|
+
/** Operation type (e.g. `CreateProducts`, `PriceUpdate`). */
|
|
693
|
+
batchRequestType?: string;
|
|
694
|
+
notes?: string;
|
|
695
|
+
/** Storage object key Trendyol uses internally for the batch payload. */
|
|
696
|
+
objectKey?: string;
|
|
697
|
+
storeFrontCode?: string;
|
|
698
|
+
/** Untouched raw response. */
|
|
699
|
+
raw: Record<string, unknown>;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Input types for Trendyol product write endpoints (V2).
|
|
704
|
+
*
|
|
705
|
+
* All five write endpoints (`createProducts`, `updateContentBulk`,
|
|
706
|
+
* `updateVariantBulk`, `updateUnapproved`, `updateDeliveryInfoBulk`) are
|
|
707
|
+
* async batch operations: SDK accepts the typed payload, Trendyol returns
|
|
708
|
+
* `{ batchRequestId }`, and the caller polls via `products.getBatchStatus`.
|
|
709
|
+
*/
|
|
710
|
+
/** Response shape for every async write endpoint in the product API. */
|
|
711
|
+
interface BatchAcceptedResponse {
|
|
712
|
+
/** Opaque ID — pass to `products.getBatchStatus(...)` to track. */
|
|
713
|
+
batchRequestId: string;
|
|
714
|
+
}
|
|
715
|
+
/** A V2 product attribute payload. Mutually-exclusive value selectors. */
|
|
716
|
+
interface ProductAttributeV2Input {
|
|
717
|
+
attributeId: number;
|
|
718
|
+
/**
|
|
719
|
+
* One or more attribute value IDs (V2 supports multi-value when the
|
|
720
|
+
* attribute's `allowMultipleAttributeValues` flag is true).
|
|
721
|
+
*/
|
|
722
|
+
attributeValueIds?: number[];
|
|
723
|
+
/** Free-text value (only when the attribute's `allowCustom` flag is true). */
|
|
724
|
+
attributeValue?: string;
|
|
725
|
+
}
|
|
726
|
+
/** Image entry: just a URL (Trendyol fetches the image asynchronously). */
|
|
727
|
+
interface ProductImageInput {
|
|
728
|
+
/** https URL; Trendyol recommends 1200×1800, 96 DPI. */
|
|
729
|
+
url: string;
|
|
730
|
+
}
|
|
731
|
+
/** Per-variant delivery option (used by `create` + `updateUnapproved`). */
|
|
732
|
+
interface DeliveryOptionInput {
|
|
733
|
+
deliveryDuration?: number;
|
|
734
|
+
fastDeliveryType?: 'SAME_DAY_SHIPPING' | 'FAST_DELIVERY';
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Payload for one item in `createProducts` (V2).
|
|
738
|
+
*
|
|
739
|
+
* Trendyol requires all 14 fields listed in the spec — the type makes them
|
|
740
|
+
* non-optional so missing required fields fail at compile time, not at
|
|
741
|
+
* runtime after a failed batch.
|
|
742
|
+
*/
|
|
743
|
+
interface CreateProductV2Input {
|
|
744
|
+
/** Barcode (≤40 chars, allows `.`, `-`, `_`). */
|
|
745
|
+
barcode: string;
|
|
746
|
+
/** Title (≤100 chars). */
|
|
747
|
+
title: string;
|
|
748
|
+
/** Parent product ID for variant grouping (≤40 chars). */
|
|
749
|
+
productMainId: string;
|
|
750
|
+
/** Trendyol numeric brand ID (from `brands.list`). */
|
|
751
|
+
brandId: number;
|
|
752
|
+
/** Trendyol numeric category ID (from `categories.list`). */
|
|
753
|
+
categoryId: number;
|
|
754
|
+
/** Initial stock quantity. */
|
|
755
|
+
quantity: number;
|
|
756
|
+
/** Seller-side stock code (≤100 chars). */
|
|
757
|
+
stockCode: string;
|
|
758
|
+
/** Desi value used for shipping cost calculation. */
|
|
759
|
+
dimensionalWeight: number;
|
|
760
|
+
/** HTML-friendly product description (≤30 000 chars). */
|
|
761
|
+
description: string;
|
|
762
|
+
/** List price (PSF). Must be ≥ `salePrice`. */
|
|
763
|
+
listPrice: number;
|
|
764
|
+
/** Sale price (TSF). */
|
|
765
|
+
salePrice: number;
|
|
766
|
+
/** 1–8 image URLs. */
|
|
767
|
+
images: ProductImageInput[];
|
|
768
|
+
/** VAT rate as integer percent (0, 1, 10, 20). */
|
|
769
|
+
vatRate: number;
|
|
770
|
+
/** Required attributes for the category — fetch via `categories.getAttributes`. */
|
|
771
|
+
attributes: ProductAttributeV2Input[];
|
|
772
|
+
/** Delivery duration / fast-delivery type. */
|
|
773
|
+
deliveryOption?: DeliveryOptionInput;
|
|
774
|
+
/** Lot/SKT info (≤100 chars). */
|
|
775
|
+
lotNumber?: string | null;
|
|
776
|
+
/** Shipment warehouse ID (from `suppliers.getAddresses`). */
|
|
777
|
+
shipmentAddressId?: number;
|
|
778
|
+
/** Returning warehouse ID. */
|
|
779
|
+
returningAddressId?: number;
|
|
780
|
+
}
|
|
781
|
+
/** Payload for one item in `updateContentBulk` (only `contentId` is required). */
|
|
782
|
+
interface UpdateContentInput {
|
|
783
|
+
/** From `Product.contentId` on `products.list` results. */
|
|
784
|
+
contentId: number;
|
|
785
|
+
title?: string;
|
|
786
|
+
description?: string;
|
|
787
|
+
images?: ProductImageInput[];
|
|
788
|
+
/**
|
|
789
|
+
* If you update ANY attribute, you must send ALL attributes — partial
|
|
790
|
+
* attribute updates are not supported by Trendyol on this endpoint.
|
|
791
|
+
*/
|
|
792
|
+
attributes?: ProductAttributeV2Input[];
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Payload for one item in `updateVariantBulk`. `barcode` is the identifier;
|
|
796
|
+
* Trendyol does not allow updating the barcode itself via this endpoint.
|
|
797
|
+
*/
|
|
798
|
+
interface UpdateVariantInput {
|
|
799
|
+
barcode: string;
|
|
800
|
+
stockCode?: string;
|
|
801
|
+
vatRate?: number;
|
|
802
|
+
shipmentAddressId?: number;
|
|
803
|
+
returningAddressId?: number;
|
|
804
|
+
dimensionalWeight?: number;
|
|
805
|
+
lotNumber?: string | null;
|
|
806
|
+
locationBasedDelivery?: 'ENABLED' | 'DISABLED' | null;
|
|
807
|
+
}
|
|
808
|
+
/** Payload for one item in `updateUnapprovedProducts` — all optional except `barcode`. */
|
|
809
|
+
interface UpdateUnapprovedInput {
|
|
810
|
+
barcode: string;
|
|
811
|
+
title?: string;
|
|
812
|
+
description?: string;
|
|
813
|
+
productMainId?: string;
|
|
814
|
+
brandId?: number;
|
|
815
|
+
categoryId?: number;
|
|
816
|
+
stockCode?: string;
|
|
817
|
+
dimensionalWeight?: number;
|
|
818
|
+
vatRate?: number;
|
|
819
|
+
deliveryOption?: DeliveryOptionInput;
|
|
820
|
+
locationBasedDelivery?: 'ENABLED' | 'DISABLED' | null;
|
|
821
|
+
lotNumber?: string | null;
|
|
822
|
+
shipmentAddressId?: number;
|
|
823
|
+
returningAddressId?: number;
|
|
824
|
+
images?: ProductImageInput[];
|
|
825
|
+
attributes?: ProductAttributeV2Input[];
|
|
826
|
+
}
|
|
827
|
+
/** Payload for one item in `updateDeliveryInfoBulk`. */
|
|
828
|
+
interface UpdateDeliveryInfoInput {
|
|
829
|
+
barcode: string;
|
|
830
|
+
deliveryOptions?: {
|
|
831
|
+
deliveryDuration?: number;
|
|
832
|
+
fastDeliveryType?: 'SAME_DAY_SHIPPING' | 'FAST_DELIVERY';
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
interface ListProductsParams extends CursorPaginationParams {
|
|
837
|
+
/** Filter by a single barcode. */
|
|
838
|
+
barcode?: string;
|
|
839
|
+
/** Filter products updated on or after this date (Trendyol expects ms-epoch). */
|
|
840
|
+
startDate?: Date;
|
|
841
|
+
/** Filter products updated on or before this date. */
|
|
842
|
+
endDate?: Date;
|
|
843
|
+
}
|
|
844
|
+
/** Date field to filter against on `listUnapproved` (default: server choice). */
|
|
845
|
+
type UnapprovedDateQueryType = 'CREATED_DATE' | 'LAST_MODIFIED_DATE';
|
|
846
|
+
interface ListUnapprovedProductsParams extends CursorPaginationParams {
|
|
847
|
+
barcode?: string;
|
|
848
|
+
startDate?: Date;
|
|
849
|
+
endDate?: Date;
|
|
850
|
+
/** Choose which date `startDate`/`endDate` apply to. */
|
|
851
|
+
dateQueryType?: UnapprovedDateQueryType;
|
|
852
|
+
/**
|
|
853
|
+
* Optional override of the seller-scoped query (rare; defaults to the
|
|
854
|
+
* client's `sellerId`).
|
|
855
|
+
*/
|
|
856
|
+
supplierId?: number;
|
|
857
|
+
}
|
|
858
|
+
/**
|
|
859
|
+
* Trendyol product read + write + lifecycle + batch-result endpoints.
|
|
860
|
+
*
|
|
861
|
+
* Rate limits (per Trendyol service limits):
|
|
862
|
+
* - filterProducts (approved + unapproved + getProductBase): 2000 req/min
|
|
863
|
+
* - getBatchRequestResult: 1000 req/min
|
|
864
|
+
* - getBuyboxInformation: 1000 req/min
|
|
865
|
+
* - create/update/archive/unlock product writes: 1000 req/min (shared bucket)
|
|
866
|
+
* - delete: 100 req/min (separate bucket)
|
|
867
|
+
*/
|
|
868
|
+
declare class ProductsResource {
|
|
869
|
+
private readonly transport;
|
|
870
|
+
private readonly sellerId;
|
|
871
|
+
private readonly filterLimiter;
|
|
872
|
+
private readonly batchLimiter;
|
|
873
|
+
private readonly buyboxLimiter;
|
|
874
|
+
private readonly writeLimiter;
|
|
875
|
+
private readonly deleteLimiter;
|
|
876
|
+
constructor(transport: TrendyolTransport, sellerId: number, options?: {
|
|
877
|
+
filterLimiter?: TokenBucketRateLimiter;
|
|
878
|
+
batchLimiter?: TokenBucketRateLimiter;
|
|
879
|
+
buyboxLimiter?: TokenBucketRateLimiter;
|
|
880
|
+
writeLimiter?: TokenBucketRateLimiter;
|
|
881
|
+
deleteLimiter?: TokenBucketRateLimiter;
|
|
882
|
+
});
|
|
883
|
+
private validateBarcodes;
|
|
884
|
+
private submitWrite;
|
|
885
|
+
/**
|
|
886
|
+
* List approved products. Use `paginate()` from `@lonca/core` to iterate
|
|
887
|
+
* lazily across pages.
|
|
888
|
+
*
|
|
889
|
+
* Trendyol exposes both page-based and `nextPageToken`-based pagination
|
|
890
|
+
* (the latter required when the dataset exceeds 10,000 items). The SDK
|
|
891
|
+
* picks the right strategy automatically — pass our opaque `cursor` from
|
|
892
|
+
* the previous response and we forward it as `nextPageToken`.
|
|
893
|
+
*
|
|
894
|
+
* @example
|
|
895
|
+
* ```ts
|
|
896
|
+
* import { paginate } from '@lonca/core';
|
|
897
|
+
* for await (const product of paginate((p) => client.products.list(p))) {
|
|
898
|
+
* for (const variant of product.variants) {
|
|
899
|
+
* console.log(variant.barcode, product.title);
|
|
900
|
+
* }
|
|
901
|
+
* }
|
|
902
|
+
* ```
|
|
903
|
+
*/
|
|
904
|
+
list(params?: ListProductsParams): Promise<CursorPage<Product>>;
|
|
905
|
+
/**
|
|
906
|
+
* Poll a batch request returned by an async write (e.g. `createProducts`,
|
|
907
|
+
* `updatePriceAndInventory`).
|
|
908
|
+
*
|
|
909
|
+
* Trendyol retains batch results for **4 hours** after the originating
|
|
910
|
+
* request — poll within that window.
|
|
911
|
+
*
|
|
912
|
+
* @param batchRequestId The opaque ID returned by the originating call.
|
|
913
|
+
*/
|
|
914
|
+
getBatchStatus(batchRequestId: string): Promise<BatchRequestResult>;
|
|
915
|
+
/**
|
|
916
|
+
* List **unapproved** (draft / rejected / pending-review) products.
|
|
917
|
+
*
|
|
918
|
+
* Wire shape is intentionally flatter than the approved-product shape:
|
|
919
|
+
* each barcode is one top-level item with `barcode`, `quantity`, `salePrice`
|
|
920
|
+
* etc. at the root. Rejected drafts carry `rejectReasonDetails` so you can
|
|
921
|
+
* surface why Trendyol's content team turned them down.
|
|
922
|
+
*
|
|
923
|
+
* Pagination follows the same convention as `list()`: `cursor` from the
|
|
924
|
+
* previous response forwards as `nextPageToken`.
|
|
925
|
+
*
|
|
926
|
+
* @example
|
|
927
|
+
* ```ts
|
|
928
|
+
* const page = await client.products.listUnapproved({ limit: 50 });
|
|
929
|
+
* for (const draft of page.items) {
|
|
930
|
+
* if (draft.status === 'rejected') {
|
|
931
|
+
* console.warn(draft.barcode, draft.rejectReasonDetails);
|
|
932
|
+
* }
|
|
933
|
+
* }
|
|
934
|
+
* ```
|
|
935
|
+
*/
|
|
936
|
+
listUnapproved(params?: ListUnapprovedProductsParams): Promise<CursorPage<UnapprovedProduct>>;
|
|
937
|
+
/**
|
|
938
|
+
* Fetch the basic lifecycle status of a single product by barcode.
|
|
939
|
+
*
|
|
940
|
+
* Cheap and useful as a polling primitive after `createProducts`: poll
|
|
941
|
+
* this endpoint until `approved` flips to `true` (or use
|
|
942
|
+
* `client.products.getBatchStatus()` to track the originating batch).
|
|
943
|
+
*
|
|
944
|
+
* @param barcode The product barcode to look up.
|
|
945
|
+
*/
|
|
946
|
+
getBase(barcode: string): Promise<ProductBase>;
|
|
947
|
+
/**
|
|
948
|
+
* Fetch buybox information for up to 10 barcodes in one call.
|
|
949
|
+
*
|
|
950
|
+
* Returns rank (`buyboxOrder === 1` means you hold the buybox), the
|
|
951
|
+
* current buybox price, and — beyond the spec — the second and third
|
|
952
|
+
* competing prices when other sellers are present.
|
|
953
|
+
*
|
|
954
|
+
* @param barcodes 1–10 product barcodes.
|
|
955
|
+
* @throws {ValidationError} when `barcodes` is empty or longer than 10.
|
|
956
|
+
*/
|
|
957
|
+
getBuyboxInfo(barcodes: string[]): Promise<BuyboxInfo[]>;
|
|
958
|
+
/**
|
|
959
|
+
* Create products (V2). Async batch — returns a `batchRequestId` you can
|
|
960
|
+
* poll with `getBatchStatus`. Max 1000 items per call.
|
|
961
|
+
*
|
|
962
|
+
* Trendyol requires the full V2 attribute payload — fetch via
|
|
963
|
+
* `categories.getAttributes` (and `categories.getAttributeValues` for
|
|
964
|
+
* values when `allowCustom === false`). Shipment / returning warehouse
|
|
965
|
+
* IDs come from `suppliers.getAddresses`.
|
|
966
|
+
*
|
|
967
|
+
* @throws {ValidationError} when `items` is empty or longer than 1000.
|
|
968
|
+
*/
|
|
969
|
+
create(items: CreateProductV2Input[]): Promise<BatchAcceptedResponse>;
|
|
970
|
+
/**
|
|
971
|
+
* Update **content** of approved products (title, description, images,
|
|
972
|
+
* attributes). Identified by `contentId`. Partial update is supported
|
|
973
|
+
* except for attributes — if you update ANY attribute, send ALL of them.
|
|
974
|
+
*
|
|
975
|
+
* @throws {ValidationError} when `items` is empty or longer than 1000.
|
|
976
|
+
*/
|
|
977
|
+
updateContent(items: UpdateContentInput[]): Promise<BatchAcceptedResponse>;
|
|
978
|
+
/**
|
|
979
|
+
* Update **variant** fields of approved products (stockCode, vatRate,
|
|
980
|
+
* dimensionalWeight, warehouse IDs, location-based delivery, lot). Identified
|
|
981
|
+
* by `barcode`. The barcode itself cannot be changed via this endpoint.
|
|
982
|
+
*
|
|
983
|
+
* @throws {ValidationError} when `items` is empty or longer than 1000.
|
|
984
|
+
*/
|
|
985
|
+
updateVariants(items: UpdateVariantInput[]): Promise<BatchAcceptedResponse>;
|
|
986
|
+
/**
|
|
987
|
+
* Update **unapproved** (draft) products. Identified by `barcode`. All
|
|
988
|
+
* other fields are optional partial updates. Use this to fix drafts that
|
|
989
|
+
* Trendyol rejected — `client.products.listUnapproved` surfaces the
|
|
990
|
+
* `rejectReasonDetails` you need to act on.
|
|
991
|
+
*
|
|
992
|
+
* **Gotcha (verified live STAGE 2026-05-25):** Trendyol's V2 spec claims
|
|
993
|
+
* only `barcode` is required, but the endpoint returns HTTP 500
|
|
994
|
+
* (`TrendyolSystemException` / `TypeError`) when too many optional fields
|
|
995
|
+
* are omitted. In practice, send at least `title`, `description`,
|
|
996
|
+
* `productMainId`, `brandId`, `categoryId`, `stockCode`,
|
|
997
|
+
* `dimensionalWeight`, `vatRate`, `images[]`, and `attributes[]` (an
|
|
998
|
+
* empty array is OK for the latter). The SDK forwards your payload
|
|
999
|
+
* as-is; trim fields only if you have verified the server accepts it.
|
|
1000
|
+
*
|
|
1001
|
+
* @throws {ValidationError} when `items` is empty or longer than 1000.
|
|
1002
|
+
*/
|
|
1003
|
+
updateUnapproved(items: UpdateUnapprovedInput[]): Promise<BatchAcceptedResponse>;
|
|
1004
|
+
/**
|
|
1005
|
+
* Update product **delivery information** (deliveryDuration,
|
|
1006
|
+
* fastDeliveryType). Identified by `barcode`.
|
|
1007
|
+
*
|
|
1008
|
+
* @throws {ValidationError} when `items` is empty or longer than 1000.
|
|
1009
|
+
*/
|
|
1010
|
+
updateDeliveryInfo(items: UpdateDeliveryInfoInput[]): Promise<BatchAcceptedResponse>;
|
|
1011
|
+
/**
|
|
1012
|
+
* Delete products by barcode. Trendyol allows deletion of unapproved
|
|
1013
|
+
* products and approved products that have been archived for more than a
|
|
1014
|
+
* day (and have not been sales-stopped by Trendyol).
|
|
1015
|
+
*
|
|
1016
|
+
* Async batch — returns `{ batchRequestId }` to poll via `getBatchStatus`.
|
|
1017
|
+
* Separately rate-limited at **100 req/min** (much tighter than create/update).
|
|
1018
|
+
*
|
|
1019
|
+
* @param barcodes 1–1000 barcodes.
|
|
1020
|
+
* @throws {ValidationError} when `barcodes` is empty or longer than 1000.
|
|
1021
|
+
*/
|
|
1022
|
+
delete(barcodes: string[]): Promise<BatchAcceptedResponse>;
|
|
1023
|
+
/**
|
|
1024
|
+
* Archive products by barcode (Trendyol's `archived=true` state).
|
|
1025
|
+
* Archived products are not visible to customers; pair with `delete`
|
|
1026
|
+
* after the 24-hour archive cool-down to remove them entirely.
|
|
1027
|
+
*
|
|
1028
|
+
* Async batch — returns `{ batchRequestId }`.
|
|
1029
|
+
*
|
|
1030
|
+
* @throws {ValidationError} when `barcodes` is empty or longer than 1000.
|
|
1031
|
+
*/
|
|
1032
|
+
archive(barcodes: string[]): Promise<BatchAcceptedResponse>;
|
|
1033
|
+
/**
|
|
1034
|
+
* Unarchive products by barcode (Trendyol's `archived=false` state).
|
|
1035
|
+
* Restores visibility for previously-archived products.
|
|
1036
|
+
*
|
|
1037
|
+
* @throws {ValidationError} when `barcodes` is empty or longer than 1000.
|
|
1038
|
+
*/
|
|
1039
|
+
unarchive(barcodes: string[]): Promise<BatchAcceptedResponse>;
|
|
1040
|
+
private setArchivedState;
|
|
1041
|
+
/**
|
|
1042
|
+
* Unlock products whose sale was paused by Trendyol due to pricing
|
|
1043
|
+
* issues (under/over-pricing, critical price error, supplier issues).
|
|
1044
|
+
* Restores selling status for the listed barcodes.
|
|
1045
|
+
*
|
|
1046
|
+
* Async batch — returns `{ batchRequestId }`.
|
|
1047
|
+
*
|
|
1048
|
+
* @throws {ValidationError} when `barcodes` is empty or longer than 1000.
|
|
1049
|
+
*/
|
|
1050
|
+
unlock(barcodes: string[]): Promise<BatchAcceptedResponse>;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
/**
|
|
1054
|
+
* The role an address plays in the seller's logistics flow.
|
|
1055
|
+
*
|
|
1056
|
+
* Trendyol allows a single physical address to play more than one role
|
|
1057
|
+
* (e.g., shipment + invoice), so always check the boolean flags rather than
|
|
1058
|
+
* relying solely on `addressType`.
|
|
1059
|
+
*/
|
|
1060
|
+
type SupplierAddressType = 'SHIPMENT' | 'RETURNING' | 'INVOICE' | 'WAREHOUSE';
|
|
1061
|
+
/**
|
|
1062
|
+
* A supplier address registered in the Trendyol Partner Panel.
|
|
1063
|
+
*
|
|
1064
|
+
* Used by `createProduct V2` for `shipmentAddressId` / `returningAddressId`.
|
|
1065
|
+
*
|
|
1066
|
+
* NOTE: The exact field set is best-effort; some optional fields may differ
|
|
1067
|
+
* once verified against real STAGE responses. Bumped fields land in a follow-up
|
|
1068
|
+
* minor release if needed.
|
|
1069
|
+
*/
|
|
1070
|
+
interface SupplierAddress {
|
|
1071
|
+
id: string;
|
|
1072
|
+
/** Free-form label set by the seller. */
|
|
1073
|
+
name?: string;
|
|
1074
|
+
/** Primary role declared by Trendyol. */
|
|
1075
|
+
addressType: SupplierAddressType;
|
|
1076
|
+
isShipmentAddress: boolean;
|
|
1077
|
+
isReturningAddress: boolean;
|
|
1078
|
+
isInvoiceAddress: boolean;
|
|
1079
|
+
isDefault: boolean;
|
|
1080
|
+
/** Multi-line address string as registered in the Partner Panel. */
|
|
1081
|
+
address?: string;
|
|
1082
|
+
city?: string;
|
|
1083
|
+
district?: string;
|
|
1084
|
+
postCode?: string;
|
|
1085
|
+
fullName?: string;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
interface SuppliersResourceOptions {
|
|
1089
|
+
/** Override the in-memory cache TTL. Defaults to 1 hour. */
|
|
1090
|
+
cacheTtlMs?: number;
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Trendyol supplier address endpoints.
|
|
1094
|
+
*
|
|
1095
|
+
* **Critical:** Trendyol rate-limits `getSuppliersAddresses` to **1 request
|
|
1096
|
+
* per hour per seller**. This resource therefore wraps the endpoint with an
|
|
1097
|
+
* in-memory cache (default TTL: 1 hour) so callers can request addresses
|
|
1098
|
+
* as often as needed without tripping the limit.
|
|
1099
|
+
*
|
|
1100
|
+
* Use `{ forceRefresh: true }` or `invalidateCache()` only when you know the
|
|
1101
|
+
* address list changed in the Partner Panel.
|
|
1102
|
+
*/
|
|
1103
|
+
declare class SuppliersResource {
|
|
1104
|
+
private readonly transport;
|
|
1105
|
+
private readonly sellerId;
|
|
1106
|
+
private cache;
|
|
1107
|
+
private readonly cacheTtlMs;
|
|
1108
|
+
private readonly limiter;
|
|
1109
|
+
private inflight;
|
|
1110
|
+
constructor(transport: TrendyolTransport, sellerId: number, options?: SuppliersResourceOptions);
|
|
1111
|
+
/**
|
|
1112
|
+
* List the seller's registered addresses (shipment, returning, invoice, warehouse).
|
|
1113
|
+
*
|
|
1114
|
+
* Returns the cached value if it is still fresh. Concurrent calls share a
|
|
1115
|
+
* single in-flight request.
|
|
1116
|
+
*/
|
|
1117
|
+
getAddresses(options?: {
|
|
1118
|
+
forceRefresh?: boolean;
|
|
1119
|
+
}): Promise<SupplierAddress[]>;
|
|
1120
|
+
/** Drop the cache; the next `getAddresses()` call hits the API. */
|
|
1121
|
+
invalidateCache(): void;
|
|
1122
|
+
private fetchFresh;
|
|
80
1123
|
}
|
|
81
1124
|
|
|
82
1125
|
interface CreateClientOptions {
|
|
@@ -107,6 +1150,11 @@ interface CreateClientOptions {
|
|
|
107
1150
|
}
|
|
108
1151
|
interface TrendyolClient {
|
|
109
1152
|
brands: BrandsResource;
|
|
1153
|
+
categories: CategoriesResource;
|
|
1154
|
+
suppliers: SuppliersResource;
|
|
1155
|
+
products: ProductsResource;
|
|
1156
|
+
inventory: InventoryResource;
|
|
1157
|
+
orders: OrdersResource;
|
|
110
1158
|
}
|
|
111
1159
|
/**
|
|
112
1160
|
* Create a Trendyol Marketplace SDK client.
|
|
@@ -127,4 +1175,4 @@ interface TrendyolClient {
|
|
|
127
1175
|
*/
|
|
128
1176
|
declare function createTrendyolClient(opts: CreateClientOptions): TrendyolClient;
|
|
129
1177
|
|
|
130
|
-
export { type Brand, BrandsResource, type CreateClientOptions, type TrendyolClient, type TrendyolEnvironment, createTrendyolClient };
|
|
1178
|
+
export { type BarcodeCategoryLookup, type BatchAcceptedResponse, type BatchRequestItemResult, type BatchRequestResult, type BatchRequestStatus, type Brand, BrandsResource, type BuyboxInfo, CategoriesResource, type Category, type CategoryAttribute, type CategoryAttributeValue, type CreateClientOptions, type CreateProductV2Input, type DeliveryOptionInput, InventoryResource, type ListCategoryAttributeValuesParams, type ListOrdersParams, type ListProductsParams, type ListUnapprovedProductsParams, type NamedRef, type OrderAddress, type OrderAddressLines, type OrderCustomer, type OrderLine, type OrderLineDiscountDetail, OrdersResource, type PackageHistoryEntry, type PriceInventoryUpdate, type Product, type ProductAttribute, type ProductAttributeV2Input, type ProductBase, type ProductImageInput, type ProductVariant, ProductsResource, type ShipmentPackage, type ShipmentPackageStatus, type SupplierAddress, type SupplierAddressType, SuppliersResource, type SuppliersResourceOptions, type TrendyolClient, type TrendyolEnvironment, type UnapprovedDateQueryType, type UnapprovedProduct, type UnapprovedProductRejectReason, type UnapprovedProductStatus, type UpdateContentInput, type UpdateDeliveryInfoInput, type UpdatePriceInventoryResponse, type UpdateUnapprovedInput, type UpdateVariantInput, createTrendyolClient };
|