peddler 5.0.0.pre.8 → 5.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ee190fadb5703ee02fa1b6ceab63a108f12320f281a276426c7b92b490395615
4
- data.tar.gz: bd4666f02e7f3bceb31ccc7b0629e4e6704b9444eb81207fd991cce13c0d007a
3
+ metadata.gz: 497c9b25616dbeb253062deda4931a5126cc95589c62592d0dbff97a7472e4d6
4
+ data.tar.gz: 79b7eb41ffe20cd88468eb666c2273dc1c171070de181c622dacf308a000f05d
5
5
  SHA512:
6
- metadata.gz: b14be992ea5c31528f7e4dbcb2721350a7c4b7c5cd8c5f1fae58ba5e78b7f7bcba1e0fa351c87e9783b9e7092521a9cf7cd1dc58082dc7e7a807ddaace604940
7
- data.tar.gz: 4d919c1be13aa6f772feac62018149065a672de3132004ba357c1d679ad54d7734fb0b716971f0176a4d027d30e28416354ed90bbf543d22d7cfa7eb003bf288
6
+ metadata.gz: d03f0b0c3b45cf707f35fb9b9faf6dbdbdae299d9fc785e8573cd22cfa8e0c86605901b15a0c11924de2f9d6c5a918f4f7e58341a9445d185f1266f85a36058d
7
+ data.tar.gz: 6140e0f80ba6810d8f544bb96ee7016b1e6d6307a33b98e5f42b8df8dd1ede7079b80e9c06c1344b0bc31f05654cd620d2027fa4485b57def42d7e615def07fe
data/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  [![Build](https://github.com/lineofflight/peddler/actions/workflows/ci.yml/badge.svg)][build]
4
4
 
5
- > **IMPORTANT:** This README is for the v5 pre-release. For the latest stable version, see the [v4.9.0 README](https://github.com/hakanensari/peddler/blob/v4.9.0/README.md).
5
+ > AI Agents: See [llms.txt](llms.txt)
6
6
 
7
- **Peddler** is a Ruby interface to the [Amazon Selling Partner API (SP-API)][api-docs]. The SP-API enables Amazon sellers and vendors to programmatically access their data on orders, shipments, payments, and more.
7
+ Peddler is a Ruby interface to the [Amazon Selling Partner API (SP-API)][api-docs]. The SP-API enables Amazon sellers and vendors to programmatically access their data on orders, shipments, payments, and more.
8
8
 
9
9
  Peddler is automatically generated from the latest Open API models provided by Amazon.
10
10
 
@@ -18,20 +18,12 @@ To begin using the Amazon SP-API, you must [register as a developer][register-as
18
18
 
19
19
  ## Installation
20
20
 
21
- Add this line to your Gemfile.
22
-
23
- ```ruby
24
- gem "peddler", "~> 5.0.0.pre.8"
25
- ```
26
-
27
- And then execute:
28
-
29
- ```shell
30
- bundle install
31
- ```
21
+ Add to your Gemfile.
32
22
 
33
23
  ## Usage
34
24
 
25
+ ### Authorization
26
+
35
27
  Set your LWA credentials in your environment.
36
28
 
37
29
  ```shell
@@ -39,14 +31,6 @@ export LWA_CLIENT_ID=<YOUR_CLIENT_ID>
39
31
  export LWA_CLIENT_SECRET=<YOUR_CLIENT_SECRET>
40
32
  ```
41
33
 
42
- Require the library.
43
-
44
- ```ruby
45
- require "peddler"
46
- ```
47
-
48
- ### Authorization
49
-
50
34
  A seller or vendor [provides you a refresh token][authorization] to access their data on Amazon.
51
35
 
52
36
  ```ruby
@@ -56,7 +40,7 @@ response = Peddler::LWA.request(
56
40
  refresh_token = response.parse.refresh_token
57
41
  ```
58
42
 
59
- You use this to generate a temporary access token to authenticate individual API requests.
43
+ Use this to generate a temporary access token to authenticate individual requests.
60
44
 
61
45
  ```ruby
62
46
  response = Peddler::LWA.request(
@@ -74,7 +58,7 @@ response = Peddler::LWA.request(
74
58
  access_token = response.parse.access_token
75
59
  ```
76
60
 
77
- If you haven't set your LWA credentials as environment variables, pass them directly when requesting the token.
61
+ In place of environment variables, you can set them directly when requesting the token.
78
62
 
79
63
  ```ruby
80
64
  response = Peddler::LWA.request(
@@ -85,9 +69,9 @@ response = Peddler::LWA.request(
85
69
  access_token = response.parse.access_token
86
70
  ```
87
71
 
88
- Access tokens are valid for one hour. To optimize performance, cache the token and reuse across calls.
72
+ Access tokens are valid for one hour. To optimize performance, cache and reuse across calls.
89
73
 
90
- In Rails, if you're storing a refresh token in a model representing a selling partner, implement a method there to retrieve and cache access tokens:
74
+ For example,
91
75
 
92
76
  ```ruby
93
77
  class Seller
@@ -103,30 +87,24 @@ end
103
87
 
104
88
  ### Rate limiting
105
89
 
106
- Amazon's SP-API imposes [rate limits][rate-limits] on operations. Override the default rate limit by passing a `:rate_limit` parameter when calling an operation.
90
+ Amazon's SP-API imposes [rate limits][rate-limits] on operations. Override the default value by passing a `:rate_limit` parameter when calling an operation.
107
91
 
108
- Provide an optional `:retries` argument when initializing an API to specify retry attempts if throttled. Default is 0 (no retries). If set to a positive value, Peddler will retry with exponential backoff based on the rate limit.
92
+ Provide an optional `:retries` argument when initializing an API to specify retry attempts if throttled. Default is 0 (no retries). If set, Peddler retries with exponential backoff.
109
93
 
110
94
  ```ruby
111
95
  api = Peddler.orders_v0.new(aws_region, access_token, retries: 3)
112
- api.get_orders(
113
- marketplaceIds: ["ATVPDKIKX0DER"],
114
- createdAfter: "2023-01-01T00:00:00Z"
115
- )
96
+ api.get_orders("...": "...")
116
97
  ```
117
98
 
118
99
  ### Typed Responses
119
100
 
120
- Peddler provides typed response parsing using the [Structure gem](https://github.com/hakanensari/structure), offering runtime type checking and better IDE support. Types are based on Ruby's [Data class](https://docs.ruby-lang.org/en/3.4/Data.html) and are lazy-loaded only when you first call `parse`.
101
+ Peddler provides typed response parsing using the [Structure gem](https://github.com/hakanensari/structure), offering runtime type checking and better IDE support. Types are based on Ruby's [Data class](https://docs.ruby-lang.org/en/3.4/Data.html) and are lazy-loaded.
121
102
 
122
103
  ```ruby
123
104
  api = Peddler.orders.new(aws_region, access_token)
124
105
 
125
106
  # Get orders with type-safe response
126
- response = api.get_orders(
127
- marketplaceIds: ["ATVPDKIKX0DER"],
128
- createdAfter: "2023-01-01T00:00:00Z"
129
- )
107
+ response = api.get_orders("...": "...")
130
108
 
131
109
  # Use .parse to get typed Data objects
132
110
  orders = response.parse.payload.orders # Returns array of Order Data objects
@@ -189,246 +167,74 @@ You can also simply use the latest version:
189
167
  api = Peddler.<api_name>.new(aws_region, access_token, options)
190
168
  ```
191
169
 
192
- Below is a comprehensive list of all available APIs organized by category:
170
+ Available APIs by category:
193
171
 
194
172
  #### Orders and Financial APIs
195
173
 
196
- - **Orders API (v0)**: Retrieve and manage orders
197
- - **Finances API (2024-06-19, 2024-06-01, v0)**: Get financial data including transaction details, payments, and refunds
198
- - **Invoices API (2024-06-19)**: Manage billing invoices
199
- - **Sales API (v1)**: Get order metrics and sales data
174
+ - **Orders API**: Retrieve and manage orders
175
+ - **Finances API**: Financial data, payments, refunds
176
+ - **Invoices API**: Manage billing invoices
177
+ - **Sales API**: Order metrics and sales data
200
178
 
201
179
  ```ruby
202
180
  api = Peddler.orders.new(aws_region, access_token)
203
- response = api.get_orders(
204
- marketplaceIds: ["ATVPDKIKX0DER"],
205
- createdAfter: "2023-01-01T00:00:00Z"
206
- )
181
+ response = api.get_orders("...": "...")
207
182
  orders = response.parse.payload.orders
208
- order_id = orders.first.amazon_order_id
209
-
210
- # Or use .to_h or .dig to parse response as a hash
211
- orders = response.dig("payload", "orders")
212
- order_id = response.dig("payload", "orders", 0, "amazonOrderId")
213
-
214
- # For sandbox testing
215
- api.sandbox.get_orders(
216
- marketplaceIds: ["ATVPDKIKX0DER"],
217
- createdAfter: "TEST_CASE_200"
218
- )
219
183
  ```
220
184
 
221
185
  #### Catalog and Listing APIs
222
186
 
223
- - **Catalog Items API (2022-04-01, 2020-12-01, v0)**: Access Amazon's catalog data
224
- - **Listings Items API (2021-08-01, 2020-09-01)**: Create and update listings
225
- - **Listings Restrictions API (2021-08-01)**: Check listing eligibility
226
- - **Product Type Definitions API (2020-09-01)**: Get schema requirements for listings
227
- - **A+ Content API (2020-11-01)**: Create and manage enhanced marketing content
228
- - **Product Pricing API (2022-05-01, v0)**: Get pricing information
229
- - **Product Fees API (v0)**: Retrieve fee estimates for products
187
+ - **Catalog Items API**: Access Amazon's catalog data
188
+ - **Listings Items API**: Create and update listings
189
+ - **Listings Restrictions API**: Check listing eligibility
190
+ - **Product Type Definitions API**: Get schema requirements for listings
191
+ - **A+ Content API**: Create and manage enhanced marketing content
192
+ - **Product Pricing API**: Get pricing information
193
+ - **Product Fees API**: Retrieve fee estimates for products
230
194
 
231
195
  ```ruby
232
196
  api = Peddler.catalog_items.new(aws_region, access_token)
233
- response = api.get_catalog_item(
234
- marketplaceIds: ["ATVPDKIKX0DER"],
235
- asin: "B08N5WRWNW"
236
- )
237
- response.parse.payload.asin # => "B08N5WRWNW"
238
-
239
- # Search catalog items by identifier
240
- response = api.search_catalog_items(
241
- ["ATVPDKIKX0DER"],
242
- identifiers: "B08N5WRWNW",
243
- identifiers_type: "ASIN"
244
- )
245
- search_results = response.parse
197
+ response = api.get_catalog_item("...": "...")
198
+ item = response.parse.payload
246
199
  ```
247
200
 
248
201
  #### Fulfillment and Inventory APIs
249
202
 
250
- - **Fulfillment Inbound API (2024-03-20, v0)**: Send inventory to FBA
251
- - **Fulfillment Outbound API (2020-07-01)**: Create and track FBA orders
252
- - **FBA Inventory API (v1)**: Manage FBA inventory quantities
253
- - **FBA Inbound Eligibility API (v1)**: Check product eligibility for FBA
254
- - **Merchant Fulfillment API (v0)**: Create shipping labels for self-fulfilled orders
255
- - **Easy Ship API (2022-03-23)**: Manage Amazon's carrier service for deliveries
256
- - **Shipping APIs (v1, v2)**: Create shipments and purchase shipping labels
257
- - **Replenishment API (2022-11-07)**: Manage inventory replenishment
258
- - **Amazon Warehousing and Distribution API (2024-05-09)**: Manage fulfillment warehousing
259
- - **Supply Sources API (2020-07-01)**: Manage supply/inventory sources
260
- - **Shipment Invoicing API (v0)**: Manage shipment-related invoices
203
+ - **Fulfillment Inbound API**: Send inventory to FBA
204
+ - **Fulfillment Outbound API**: Create and track FBA orders
205
+ - **FBA Inventory API**: Manage FBA inventory quantities
206
+ - **FBA Inbound Eligibility API**: Check product eligibility for FBA
207
+ - **Merchant Fulfillment API**: Create shipping labels for self-fulfilled orders
208
+ - **Easy Ship API**: Manage Amazon's carrier service
209
+ - **Shipping APIs**: Create shipments and purchase shipping labels
210
+ - **Replenishment API**: Manage inventory replenishment
211
+ - **Amazon Warehousing and Distribution API**: Manage fulfillment warehousing
212
+ - **Supply Sources API**: Manage supply/inventory sources
213
+ - **Shipment Invoicing API**: Manage shipment-related invoices
261
214
 
262
215
  ```ruby
263
- # FBA outbound example
264
216
  api = Peddler.fulfillment_outbound.new(aws_region, access_token)
265
- api.create_fulfillment_order(
266
- body: {
267
- sellerFulfillmentOrderId: "ORDER123",
268
- displayableOrderId: "ORDER123",
269
- displayableOrderDate: Time.now.iso8601,
270
- shippingSpeedCategory: "Standard",
271
- destinationAddress: {
272
- name: "Customer Name",
273
- addressLine1: "123 Main St",
274
- city: "Seattle",
275
- stateOrRegion: "WA",
276
- postalCode: "98101",
277
- countryCode: "US"
278
- },
279
- items: [
280
- {
281
- sellerSku: "SKU123",
282
- sellerFulfillmentOrderItemId: "ITEM123",
283
- quantity: 1
284
- }
285
- ]
286
- }
287
- )
217
+ response = api.create_fulfillment_order(body: { "...": "..." })
288
218
  ```
289
219
 
290
220
  #### Data Management APIs
291
221
 
292
- - **Feeds API (2021-06-30)**: Upload data to Amazon to update listings, prices, inventory, and more
293
- - **Reports API (2021-06-30)**: Request and download reports about orders, inventory, fulfillment, and more
294
- - **Uploads API (2020-11-01)**: Upload files for various SP-API operations
295
- - **Data Kiosk API (2023-11-15, 2024-03-15, 2024-04-24, 2024-09-30)**: Access and manage analytical data with GraphQL queries
222
+ - **Feeds API**: Upload data to Amazon (listings, prices, inventory, etc.)
223
+ - **Reports API**: Request and download reports (orders, inventory, fulfillment, etc.)
224
+ - **Uploads API**: Upload files for various SP-API operations
225
+ - **Data Kiosk API**: Access analytical data with GraphQL queries
296
226
 
297
227
  ```ruby
228
+ # Feeds API - create feed document, upload, submit
298
229
  api = Peddler.feeds.new(aws_region, access_token)
299
-
300
- # Complete Feeds API Workflow:
301
- # 1. Create a feed document (input feed document)
302
- # 2. Upload content to the document
303
- # 3. Create feed referencing the document
304
- # 4. Wait for feed to complete (e.g., SQS notification)
305
- # 5. Get feed document (result feed document)
306
- # 6. Download results to see processing outcome
307
-
308
- # Step 1: Create feed document (input document)
309
- document_response = api.create_feed_document(
310
- contentType: "text/xml; charset=UTF-8"
311
- )
312
-
313
- # The `dig` method safely navigates the response hash
314
- # If the response structure is:
315
- # {
316
- # "feedDocumentId": "amzn1.tortuga.3.abc123...",
317
- # "url": "...",
318
- # "encryptionDetails": {
319
- # "standard": "AES",
320
- # "key": "encryption-key",
321
- # "initializationVector": "vector-value"
322
- # }
323
- # }
324
-
325
- # Access top-level keys with dig
326
- feed_document_id = document_response.dig("feedDocumentId")
327
- upload_url = document_response.dig("url")
328
-
329
- # Access nested keys - returns nil if any key in the path is missing
330
- encryption_key = document_response.dig("encryptionDetails", "key")
331
-
332
- # Step 2: Upload feed content to the input document
333
- feed_content = File.read("inventory_update.xml")
334
- api.upload_feed_document(upload_url, feed_content, "text/xml; charset=UTF-8")
335
-
336
- # Step 3: Create feed referencing the input document
337
- feed_response = api.create_feed(
338
- feedType: "POST_INVENTORY_AVAILABILITY_DATA",
339
- marketplaceIds: ["ATVPDKIKX0DER"],
340
- inputFeedDocumentId: feed_document_id
341
- )
342
- feed_id = feed_response.dig("feedId")
343
-
344
- # Step 4: Wait for feed to complete (polling or SQS notification)
345
- # Poll until status is "DONE", "FATAL", or "CANCELLED"
346
- loop do
347
- feed_status = api.get_feed(feed_id)
348
- status = feed_status.dig("processingStatus")
349
- break if ["DONE", "FATAL", "CANCELLED"].include?(status)
350
- sleep 30 # Wait 30 seconds before checking again
351
- end
352
-
353
- # Step 5: Get feed document (result document with processing results)
354
- result_document_id = feed_status.dig("resultFeedDocumentId")
355
- result_document = api.get_feed_document(result_document_id) if result_document_id
356
-
357
- # Step 6: Download results to see processing outcome
358
- if result_document
359
- download_url = result_document.dig("url")
360
- response = HTTP.get(download_url)
361
- content = if result_document.dig("compressionAlgorithm") == "GZIP"
362
- Zlib::GzipReader.new(response).read
363
- else
364
- response.to_s
365
- end
366
- # Parse content to check for errors/success
367
- end
368
-
369
- # JSON feed example
370
- json_document = api.create_feed_document(
371
- { "contentType" => "application/json; charset=UTF-8" }
372
- )
373
- json_feed_content = JSON.generate({
374
- "header": {
375
- "sellerId": "SELLER_ID",
376
- "version": "2.0",
377
- "issueLocale": "en_US"
378
- },
379
- "messages": [
380
- {
381
- "messageId": 1,
382
- "sku": "SKU123",
383
- "operationType": "UPDATE",
384
- "productType": "PRODUCT",
385
- "attributes": {
386
- # Your product attributes here
387
- }
388
- }
389
- ]
390
- })
391
- api.upload_feed_document(json_document.dig("url"), json_feed_content, "application/json; charset=UTF-8")
392
- ```
393
-
394
- **Parsing Feed Results:**
395
-
396
- After feed processing completes, parse the result document with type-safe data classes:
397
-
398
- ```ruby
399
- # Get feed processing result document
400
- result_document = api.get_feed_document(result_feed_document_id)
401
- result_content = HTTP.get(result_document.dig("url")).to_s
402
-
403
- # Handle compression if needed
404
- if result_document.dig("compressionAlgorithm") == "GZIP"
405
- require "zlib"
406
- result_content = Zlib::GzipReader.new(StringIO.new(result_content)).read
407
- end
408
-
409
- # Parse with type safety
410
- result_json = JSON.parse(result_content)
411
- report = Peddler::Feeds::ListingsFeedProcessingReportSchema.parse(result_json)
412
-
413
- # Access structured processing results
414
- puts "Messages Processed: #{report.summary.messages_processed}"
415
- puts "Messages Accepted: #{report.summary.messages_accepted}"
416
- puts "Messages with Errors: #{report.summary.messages_with_error}"
417
- puts "Messages with Warnings: #{report.summary.messages_with_warning}"
418
-
419
- # Iterate through issues with type-safe access
420
- report.issues.each do |issue|
421
- puts "\nIssue in message #{issue.message_id}:"
422
- puts " Severity: #{issue.severity}"
423
- puts " Code: #{issue.code}"
424
- puts " Message: #{issue.message}"
425
- puts " SKU: #{issue.sku}" if issue.sku
426
- end
230
+ document = api.create_feed_document(contentType: "text/xml; charset=UTF-8")
231
+ api.upload_feed_document(document.dig("url"), File.read("feed.xml"), "text/xml")
232
+ feed = api.create_feed(feedType: "POST_INVENTORY_AVAILABILITY_DATA", marketplaceIds: ["ATVPDKIKX0DER"], inputFeedDocumentId: document.dig("feedDocumentId"))
427
233
  ```
428
234
 
429
235
  #### Data Kiosk API
430
236
 
431
- The Data Kiosk API provides access to Amazon's analytical data through GraphQL queries. Peddler supports four Data Kiosk schema versions, each with type-safe Structure classes for parsing responses.
237
+ The Data Kiosk API provides access to Amazon's analytical data through GraphQL queries. Peddler supports four Data Kiosk schema versions, each with type-safe classes for parsing responses.
432
238
 
433
239
  **Available Schemas:**
434
240
 
@@ -437,543 +243,50 @@ The Data Kiosk API provides access to Amazon's analytical data through GraphQL q
437
243
  - **Economics20240315**: Economics and profitability data
438
244
  - **VendorAnalytics20240930**: Vendor-specific analytics and forecasting data
439
245
 
440
- **Basic Example:**
441
-
442
246
  ```ruby
443
247
  api = Peddler.data_kiosk.new(aws_region, access_token)
444
-
445
- # Create a Data Kiosk query request
446
- response = api.create_query({
447
- query: """
448
- query {
449
- salesAndTrafficByDate(
450
- startDate: "2024-01-01",
451
- endDate: "2024-01-31",
452
- marketplaceIds: ["ATVPDKIKX0DER"]
453
- ) {
454
- data {
455
- date
456
- orderItems
457
- sales
458
- pageViews
459
- sessions
460
- }
461
- }
462
- }
463
- """
464
- })
465
-
466
- # Get the query ID
248
+ response = api.create_query(query: "query { salesAndTrafficByDate(...) { data { date sales } } }")
467
249
  query_id = response.dig("payload", "queryId")
468
-
469
- # Poll for query completion
470
- loop do
471
- status = api.get_query(query_id)
472
- processing_status = status.dig("payload", "processingStatus")
473
- break if ["DONE", "FATAL"].include?(processing_status)
474
- sleep 2
475
- end
476
-
477
- # Download the report document
478
- result_document_id = status.dig("payload", "reportDocumentId")
479
- document = api.get_report_document(result_document_id)
480
- report_url = document.dig("url")
481
-
482
- # Parse the response
483
- require "net/http"
484
- http_response = HTTP.get(report_url)
485
- parsed_data = JSON.parse(http_response.to_s)
486
-
487
- # Use type-safe parsing with Peddler's Structure classes
488
- sales_data = Peddler::DataKiosk::SalesAndTraffic20231115.parse(parsed_data)
489
- ```
490
-
491
- **Query Document Management:**
492
-
493
- Peddler provides a helper method for downloading query documents:
494
-
495
- ```ruby
496
- api = Peddler.data_kiosk.new(aws_region, access_token)
497
-
498
- # Download a query document by ID (v2023-11-15 schemas)
499
- document = api.download_query_document("amzn1.tortuga.3.abc123...")
500
-
501
- # Or pass a full URL
502
- document = api.download_query_document("https://...")
503
- ```
504
-
505
- **Type-Safe Response Parsing:**
506
-
507
- Each Data Kiosk schema version includes type-safe Structure classes that match the GraphQL response structure:
508
-
509
- ```ruby
510
- # Parse economics data
511
- response_data = JSON.parse(query_response_body)
512
- analytics = Peddler::DataKiosk::Economics20240315.parse(response_data)
513
-
514
- # Access typed attributes
515
- analytics.analytics_economics_2024_03_15.each do |record|
516
- puts "Sales: #{record.sales}"
517
- puts "Fees: #{record.fees}"
518
- puts "Net Proceeds: #{record.net_proceeds}"
519
- puts "Date Range: #{record.start_date} to #{record.end_date}"
520
- end
521
- ```
522
-
523
- **Query Examples by Schema:**
524
-
525
- ```ruby
526
- # Sales and Traffic by ASIN (2023-11-15)
527
- query_sales_asin = """
528
- query {
529
- salesAndTrafficByAsin(
530
- startDate: "2024-01-01",
531
- endDate: "2024-01-31",
532
- marketplaceIds: ["ATVPDKIKX0DER"]
533
- ) {
534
- data {
535
- startDate
536
- endDate
537
- parentAsin
538
- childAsin
539
- sku
540
- sales {
541
- orderedProductSales
542
- totalOrderItems
543
- unitsOrdered
544
- }
545
- traffic {
546
- pageViews
547
- pageViewsPercentage
548
- sessions
549
- sessionPercentage
550
- unitSessionPercentage
551
- }
552
- }
553
- }
554
- }
555
- """
556
-
557
- # Economics data (2024-03-15)
558
- query_economics = """
559
- query {
560
- analytics {
561
- economics {
562
- data {
563
- endDate
564
- startDate
565
- parentAsin
566
- sales {
567
- orderedProductSales
568
- netProductSales
569
- }
570
- fees {
571
- feeType
572
- chargeAmount
573
- }
574
- netProceeds {
575
- total
576
- perUnit
577
- }
578
- }
579
- }
580
- }
581
- }
582
- """
583
-
584
- # Vendor analytics (2024-09-30)
585
- query_vendor = """
586
- query {
587
- analytics {
588
- vendoranalytics {
589
- manufacturingView {
590
- startDate
591
- endDate
592
- metrics {
593
- costs
594
- traffic
595
- orders
596
- }
597
- }
598
- }
599
- }
600
- }
601
- """
602
- ```
603
-
604
- #### Communication and Customer Management APIs
605
-
606
- - **Customer Feedback API (2024-06-01)**: Analyze customer reviews and returns data at item and browse node levels
607
- - **Notifications API (v1)**: Subscribe to notifications for events like order updates
608
- - **Messaging API (v1)**: Send messages to customers
609
- - **Solicitations API (v1)**: Request customer reviews
610
-
611
- ```ruby
612
- # Customer Feedback API example
613
- api = Peddler.customer_feedback_2024_06_01.new(aws_region, access_token)
614
-
615
- # Get item review topics (most positive and negative)
616
- review_topics = api.get_item_review_topics(
617
- "B08N5WRWNW", # ASIN
618
- Marketplace.id("US"),
619
- "frequency" # Sort by frequency
620
- )
621
-
622
- # Get item review trends for past 6 months
623
- review_trends = api.get_item_review_trends(
624
- "B08N5WRWNW",
625
- Marketplace.id("US")
626
- )
627
-
628
- # Get browse node return topics
629
- return_topics = api.get_browse_node_return_topics(
630
- "123456789", # Browse node ID
631
- Marketplace.id("US")
632
- )
633
- ```
634
-
635
- ```ruby
636
- api = Peddler.notifications.new(aws_region, access_token)
637
- # Create destination
638
- destination = api.create_destination(
639
- name: "MyEventQueue",
640
- resourceSpecification: {
641
- sqs: { arn: "arn:aws:sqs:us-east-1:123456789012:MyQueue" }
642
- }
643
- )
644
- destination_id = destination.dig("payload", "destinationId")
645
-
646
- # Create subscription
647
- api.create_subscription(
648
- notificationType: "ANY_OFFER_CHANGED",
649
- destinationId: destination_id,
650
- payloadVersion: "1"
651
- )
652
-
653
- # For sandbox testing (requires grantless token)
654
- sandbox_api = Peddler.notifications.new(aws_region, grantless_access_token)
655
- sandbox_api = sandbox_api.sandbox
656
- # Get all destinations
657
- destinations = sandbox_api.get_destinations
658
-
659
- # Get specific subscription
660
- subscription = sandbox_api.get_subscription("LISTINGS_ITEM_ISSUES_CHANGE")
661
- ```
662
-
663
- **Parsing Notifications:**
664
-
665
- Once you receive notifications (via SQS or EventBridge), parse them with type-safe data classes:
666
-
667
- ```ruby
668
- # Parse notification from SQS message
669
- notification_json = JSON.parse(sqs_message.body)
670
- notification = Peddler::Notifications::AnyOfferChanged.parse(notification_json)
671
-
672
- # Type-safe access to notification data
673
- notification.notification_version # => "1.0"
674
- notification.notification_type # => "ANY_OFFER_CHANGED"
675
-
676
- # Access payload with autocomplete
677
- notification.payload.offers.each do |offer|
678
- puts "Seller: #{offer.seller_id}"
679
- puts "Price: #{offer.listing_price.amount} #{offer.listing_price.currency_code}"
680
- puts "Condition: #{offer.item_condition}"
681
- puts "Prime: #{offer.is_prime?}" if offer.respond_to?(:is_prime?)
682
- end
250
+ # Poll for completion and download document
683
251
  ```
684
-
685
252
  #### Vendor APIs
686
253
 
687
- APIs for vendors selling to Amazon:
688
-
689
- - **Vendor Orders API (v1)**: Retrieve purchase orders
690
- - **Vendor Direct Fulfillment Orders API (2021-12-28, v1)**: Manage direct fulfillment orders
691
- - **Vendor Direct Fulfillment Shipping API (2021-12-28, v1)**: Manage shipping for direct fulfillment
692
- - **Vendor Direct Fulfillment Payments API (v1)**: Process payments for direct fulfillment
693
- - **Vendor Direct Fulfillment Inventory API (v1)**: Manage inventory for direct fulfillment
694
- - **Vendor Direct Fulfillment Transactions API (2021-12-28, v1)**: Track transaction status
695
- - **Vendor Direct Fulfillment Sandbox Test Data API (2021-10-28)**: Generate test data in sandbox
696
- - **Vendor Shipments API (v1)**: Track vendor shipments
697
- - **Vendor Invoices API (v1)**: Submit and track invoices
698
- - **Vendor Transaction Status API (v1)**: Check transaction status
254
+ - **Vendor Orders API**: Retrieve purchase orders
255
+ - **Vendor Direct Fulfillment Orders API**: Manage direct fulfillment orders
256
+ - **Vendor Direct Fulfillment Shipping API**: Manage shipping for direct fulfillment
257
+ - **Vendor Direct Fulfillment Payments API**: Process payments for direct fulfillment
258
+ - **Vendor Direct Fulfillment Inventory API**: Manage inventory for direct fulfillment
259
+ - **Vendor Direct Fulfillment Transactions API**: Track transaction status
260
+ - **Vendor Direct Fulfillment Sandbox Test Data API**: Generate test data in sandbox
261
+ - **Vendor Shipments API**: Track vendor shipments
262
+ - **Vendor Invoices API**: Submit and track invoices
263
+ - **Vendor Transaction Status API**: Check transaction status
699
264
 
700
265
  ```ruby
701
266
  api = Peddler.vendor_orders.new(aws_region, access_token)
702
- orders = api.get_purchase_orders(
703
- limit: 10,
704
- createdAfter: "2023-01-01T00:00:00Z"
705
- ).parse
267
+ orders = api.get_purchase_orders(limit: 10, createdAfter: "2023-01-01T00:00:00Z").parse
706
268
  ```
707
269
 
708
270
  #### Authorization and Account Management APIs
709
271
 
710
- - **Application Management API (2023-11-30)**: Manage application authorization
711
- - **Tokens API (2021-03-01)**: Generate restricted data tokens for accessing PII
712
- - **Sellers API (v1)**: Get seller account information and marketplace participation
713
- - **Services API (v1)**: Manage seller services and subscriptions
714
- - **Seller Wallet API (2024-03-01)**: Manage seller financial accounts
715
- - **Application Integrations API (2024-04-01)**: Manage app integrations
716
- - **Vehicles API (2024-11-01)**: Manage vehicle data for automotive products
717
-
718
- ### Additional API Examples
719
-
720
- #### Product Pricing API
721
-
722
- ```ruby
723
- # Using Product Pricing v0
724
- api = Peddler.product_pricing_v0.new(aws_region, access_token)
725
-
726
- # Get pricing information for an ASIN
727
- pricing = api.get_pricing(
728
- Marketplace.id("US"),
729
- "Asin",
730
- asins: ["B08N5WRWNW"]
731
- )
732
-
733
- # Get competitive pricing for an ASIN
734
- competitive = api.get_competitive_pricing(
735
- Marketplace.id("US"),
736
- "Asin",
737
- asins: ["B08N5WRWNW"]
738
- )
739
-
740
- # Get offers for a specific item
741
- offers = api.get_item_offers(
742
- Marketplace.id("US"),
743
- "New",
744
- "B08N5WRWNW"
745
- )
746
-
747
- # Batch request for multiple items (2022-05-01 API)
748
- api = Peddler.product_pricing_2022_05_01.new(aws_region, access_token)
749
- batch_request = {
750
- requests: [
751
- {
752
- uri: "/products/pricing/2022-05-01/items/competitiveSummary",
753
- method: "GET",
754
- asin: "B08N5WRWNW",
755
- marketplaceId: Marketplace.id("US"),
756
- includedData: ["featuredBuyingOptions", "referencePrices", "lowestPricedOffers"]
757
- },
758
- # Additional items...
759
- ]
760
- }
761
- results = api.get_competitive_summary(batch_request)
762
- ```
763
-
764
- #### Listings Items API
765
-
766
- ```ruby
767
- api = Peddler.listings_items.new(aws_region, access_token)
768
-
769
- # Create or update a listing
770
- listing_result = api.put_listings_item(
771
- "SELLER_ID",
772
- "SKU123",
773
- Marketplace.id("US"),
774
- {
775
- productType: "PRODUCT",
776
- requirements: "LISTING_OFFER_ONLY",
777
- attributes: {
778
- merchant_suggested_asin: [{
779
- value: "B08N5WRWNW",
780
- marketplace_id: Marketplace.id("US")
781
- }],
782
- condition_type: [{
783
- value: "new_new",
784
- marketplace_id: Marketplace.id("US")
785
- }],
786
- # Additional attributes...
787
- }
788
- }
789
- )
790
-
791
- # Update specific listing elements with JSON Patch
792
- patch_result = api.patch_listings_item(
793
- "SELLER_ID",
794
- "SKU123",
795
- Marketplace.id("US"),
796
- {
797
- productType: "PRODUCT",
798
- patches: [
799
- {
800
- op: "replace",
801
- path: "/attributes/purchasable_offer",
802
- value: [{
803
- currency: "USD",
804
- our_price: [{
805
- schedule: [{
806
- value_with_tax: 39.99
807
- }]
808
- }]
809
- }]
810
- }
811
- ]
812
- }
813
- )
814
-
815
- # Get listing details
816
- listing = api.get_listings_item(
817
- "SELLER_ID",
818
- "SKU123",
819
- Marketplace.id("US"),
820
- included_data: "attributes,issues"
821
- )
822
-
823
- # Delete a listing
824
- api.delete_listings_item("SELLER_ID", "SKU123", Marketplace.id("US"))
825
- ```
826
-
827
- #### Listings Restrictions API
272
+ - **Application Management API**: Manage application authorization
273
+ - **Tokens API**: Generate restricted data tokens for accessing PII
274
+ - **Sellers API**: Get seller account information and marketplace participation
275
+ - **Services API**: Manage seller services and subscriptions
276
+ - **Seller Wallet API**: Manage seller financial accounts
277
+ - **Application Integrations API**: Manage app integrations
278
+ - **Vehicles API**: Manage vehicle data for automotive products
828
279
 
829
- ```ruby
830
- api = Peddler.listings_restrictions.new(aws_region, access_token)
831
-
832
- # Check restrictions for an ASIN
833
- restrictions = api.get_listings_restrictions(
834
- "B08N5WRWNW",
835
- "SELLER_ID",
836
- Marketplace.id("US"),
837
- condition_type: "new_new"
838
- )
839
- ```
840
-
841
- #### Product Type Definitions API
842
-
843
- ```ruby
844
- api = Peddler.product_type_definitions.new(aws_region, access_token)
845
-
846
- # Get schema for a product type
847
- definition = api.get_definitions_product_type(
848
- "PRODUCT",
849
- Marketplace.id("US"),
850
- requirements: "LISTING_OFFER_ONLY"
851
- )
852
-
853
- # Download the JSON schema
854
- schema_url = definition.dig("schema", "link", "resource")
855
- json_schema = HTTP.get(schema_url).parse(:json)
856
- ```
857
-
858
- #### Reports API
859
-
860
- ```ruby
861
- api = Peddler.reports.new(aws_region, access_token)
862
-
863
- # Request a report
864
- report_response = api.create_report({
865
- "reportType" => "GET_MERCHANTS_LISTINGS_FYP_REPORT",
866
- "marketplaceIds" => Marketplace.ids("US")
867
- })
868
- report_id = report_response.dig("reportId")
869
-
870
- # Get report status
871
- report = api.get_report(report_id)
872
-
873
- # Get all reports of a specific type
874
- reports = api.get_reports(report_types: ["GET_MERCHANTS_LISTINGS_FYP_REPORT"])
875
-
876
- # Download a report document (using convenience helper)
877
- response = api.download_report_document("DOCUMENT_ID")
878
- # Process the downloaded report content from response.body...
879
- ```
880
-
881
- #### Understanding Report Types
882
-
883
- SP-API provides two different types of reports with different formats and APIs:
280
+ ### Complex Workflows
884
281
 
885
- **1. Modern JSON-Based Reports** (Recommended)
282
+ Detailed workflows are available in test files with VCR cassettes:
886
283
 
887
- These are structured analytics reports that return JSON data with defined schemas. Peddler provides type-safe data classes for these reports using the Structure gem.
284
+ - **Feeds API**: [test/peddler/apis/feeds_2021_06_30_test.rb](test/peddler/apis/feeds_2021_06_30_test.rb)
285
+ - **Data Kiosk API**: [test/peddler/apis/data_kiosk_2023_11_15_test.rb](test/peddler/apis/data_kiosk_2023_11_15_test.rb)
286
+ - **Reports API**: [lib/peddler/apis/reports_2021_06_30.rb](lib/peddler/apis/reports_2021_06_30.rb) (YARD docs)
287
+ - **Notifications API**: [lib/peddler/notifications/](lib/peddler/notifications/) (type-safe parsing)
888
288
 
889
- Examples:
890
- - Vendor Real-Time Inventory Report
891
- - Seller Sales and Traffic Report
892
- - Account Health Report
893
- - Vendor Forecasting Report
894
- - Customer Feedback Reports
895
-
896
- Location in Peddler: `lib/peddler/reports/` with generated Structure-based classes
897
-
898
- ```ruby
899
- # Example: Request and parse a vendor real-time inventory report
900
- api = Peddler.reports.new(aws_region, access_token)
901
-
902
- # Create report request
903
- report_response = api.create_report({
904
- "reportType" => "GET_VENDOR_REAL_TIME_INVENTORY_REPORT",
905
- "marketplaceIds" => [Marketplace.id("US")],
906
- "reportOptions" => {
907
- "reportPeriod" => "WEEK",
908
- "distributorView" => "MANUFACTURING",
909
- "sellingProgram" => "RETAIL",
910
- "startDate" => "2024-01-01",
911
- "endDate" => "2024-01-07"
912
- }
913
- })
914
-
915
- # Wait for report to be ready, then download
916
- report_id = report_response.dig("reportId")
917
- # ... check status until DONE ...
918
- document_id = api.get_report(report_id).dig("reportDocumentId")
919
-
920
- # Download and parse JSON report
921
- document = api.get_report_document(document_id)
922
- report_json = HTTP.get(document.dig("url")).parse(:json)
923
-
924
- # Use typed data classes
925
- report = Peddler::Reports::VendorRealTimeInventory::Report.new(report_json)
926
- report.report_data.each do |data|
927
- puts "ASIN: #{data.asin}, Inventory: #{data.highly_available_inventory}"
928
- end
929
- ```
930
-
931
- **2. Legacy Flat-File Reports** (Tab-Delimited)
932
-
933
- These are older reports that return tab-delimited text files (TSV format), often GZIP compressed. These require manual CSV parsing and do NOT have Structure-based data classes.
934
-
935
- Examples:
936
- - `GET_MERCHANT_LISTINGS_ALL_DATA`
937
- - `GET_FBA_MYI_UNSUPPRESSED_INVENTORY_DATA`
938
- - `GET_FLAT_FILE_ALL_ORDERS_DATA_BY_LAST_UPDATE_GENERAL`
939
-
940
- These must be parsed manually using Ruby's CSV library:
941
-
942
- ```ruby
943
- # Download flat-file report
944
- document = api.get_report_document(document_id)
945
- response = HTTP.get(document.dig("url"))
946
-
947
- # Handle GZIP compression if needed
948
- body = if document.dig("compressionAlgorithm") == "GZIP"
949
- Zlib::GzipReader.new(StringIO.new(response.body.to_s)).read
950
- else
951
- response.body.to_s
952
- end
953
-
954
- # Parse tab-delimited data
955
- csv_options = {
956
- col_sep: "\t",
957
- headers: true,
958
- quote_char: "\x00",
959
- encoding: "UTF-8"
960
- }
961
- CSV.parse(body, **csv_options) do |row|
962
- # Process each row as a hash
963
- puts "SKU: #{row['sku']}, ASIN: #{row['asin']}, Quantity: #{row['quantity']}"
964
- end
965
- ```
966
-
967
- For a complete list of report types and their formats, see the [Report Type Values documentation](https://developer-docs.amazon.com/sp-api/docs/report-type-values).
968
-
969
- #### Sellers API
970
-
971
- ```ruby
972
- api = Peddler.sellers.new(aws_region, access_token)
973
-
974
- # Get marketplace participations
975
- participations = api.get_marketplace_participations
976
- ```
289
+ For complete method signatures, see [sig/peddler/apis/](sig/peddler/apis/)
977
290
 
978
291
  For a complete list of available APIs and their detailed documentation, refer to the [API models repository][swagger-models].
979
292
 
@@ -12,7 +12,7 @@ module Peddler
12
12
  # report would contain data for each complete hour within the time span.
13
13
  Report = Structure.new do
14
14
  # @return [Array<reportData>] List of hour and ASIN combinations.
15
- attribute(:report_data, Array, from: "reportData")
15
+ attribute(:report_data, [ReportData], from: "reportData")
16
16
 
17
17
  # @return [Hash] Summarizes the original report request.
18
18
  attribute(:report_specification, ReportSpecification, from: "reportSpecification")
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Peddler
4
- VERSION = "5.0.0.pre.8"
4
+ VERSION = "5.0.0"
5
5
  end
@@ -2,20 +2,20 @@ module Peddler
2
2
  module Reports
3
3
  module VendorRealTimeSales
4
4
  class Report < Data
5
- def self.new: (report_data: Array[untyped]?, report_specification: Peddler::Reports::VendorRealTimeSales::ReportSpecification?) -> Peddler::Reports::VendorRealTimeSales::Report
6
- | (Array[untyped]?, Peddler::Reports::VendorRealTimeSales::ReportSpecification?) -> Peddler::Reports::VendorRealTimeSales::Report
7
- def self.[]: (report_data: Array[untyped]?, report_specification: Peddler::Reports::VendorRealTimeSales::ReportSpecification?) -> Peddler::Reports::VendorRealTimeSales::Report
8
- | (Array[untyped]?, Peddler::Reports::VendorRealTimeSales::ReportSpecification?) -> Peddler::Reports::VendorRealTimeSales::Report
5
+ def self.new: (report_data: Array[Peddler::Reports::VendorRealTimeSales::ReportData]?, report_specification: Peddler::Reports::VendorRealTimeSales::ReportSpecification?) -> Peddler::Reports::VendorRealTimeSales::Report
6
+ | (Array[Peddler::Reports::VendorRealTimeSales::ReportData]?, Peddler::Reports::VendorRealTimeSales::ReportSpecification?) -> Peddler::Reports::VendorRealTimeSales::Report
7
+ def self.[]: (report_data: Array[Peddler::Reports::VendorRealTimeSales::ReportData]?, report_specification: Peddler::Reports::VendorRealTimeSales::ReportSpecification?) -> Peddler::Reports::VendorRealTimeSales::Report
8
+ | (Array[Peddler::Reports::VendorRealTimeSales::ReportData]?, Peddler::Reports::VendorRealTimeSales::ReportSpecification?) -> Peddler::Reports::VendorRealTimeSales::Report
9
9
 
10
10
  def self.members: () -> [ :report_data, :report_specification ]
11
11
 
12
12
  def self.parse: (?Hash[String | Symbol, untyped], **untyped) -> Peddler::Reports::VendorRealTimeSales::Report
13
13
 
14
- attr_reader report_data: Array[untyped]?
14
+ attr_reader report_data: Array[Peddler::Reports::VendorRealTimeSales::ReportData]?
15
15
  attr_reader report_specification: Peddler::Reports::VendorRealTimeSales::ReportSpecification?
16
16
 
17
17
  def members: () -> [ :report_data, :report_specification ]
18
- def to_h: () -> { report_data: Array[untyped]?, report_specification: Peddler::Reports::VendorRealTimeSales::ReportSpecification? }
18
+ def to_h: () -> { report_data: Array[Peddler::Reports::VendorRealTimeSales::ReportData]?, report_specification: Peddler::Reports::VendorRealTimeSales::ReportSpecification? }
19
19
  end
20
20
 
21
21
  class ReportData < Data
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: peddler
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0.pre.8
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hakan Ensari