@henkey/n8n-nodes-amazon-paapi
Version:
n8n node for Amazon Affiliate API (PA API 5.0) with enhanced features including OffersV2 support, advanced filtering, and better error handling
595 lines (594 loc) • 30.7 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.AmazonPA = void 0;
const amazonPaapi = __importStar(require("amazon-paapi"));
class AmazonPA {
constructor() {
this.description = {
displayName: 'Amazon PA API',
name: 'amazonPA',
icon: 'file:amazon.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["operation"]}}',
description: 'Interact with Amazon Product Advertising API 5.0 (PAAPI)',
defaults: {
name: 'Amazon PA API',
color: '#FF9900',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'amazonPaApi',
required: true,
},
],
properties: [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
options: [
{
name: 'Search Items',
value: 'searchItems',
description: 'Search for items on Amazon',
},
{
name: 'Get Items',
value: 'getItems',
description: 'Get item information by ASIN',
},
{
name: 'Get Browse Nodes',
value: 'getBrowseNodes',
description: 'Get browse node information',
},
{
name: 'Get Variations',
value: 'getVariations',
description: 'Get variations for a parent ASIN',
},
],
default: 'searchItems',
},
{
displayName: 'Partner Tag',
name: 'partnerTag',
type: 'string',
default: '',
description: 'Amazon Partner Tag (overrides default if set)',
},
{
displayName: 'Item IDs (for Get Items)',
name: 'itemIds',
type: 'string',
displayOptions: {
show: {
operation: ['getItems'],
},
},
default: '',
description: 'Comma-separated list of ASINs for items',
},
{
displayName: 'ASIN (for Get Variations)',
name: 'variationAsin',
type: 'string',
displayOptions: {
show: {
operation: ['getVariations'],
},
},
default: '',
description: 'Parent ASIN to get variations for',
},
{
displayName: 'Keywords (for Search Items)',
name: 'keywords',
type: 'string',
displayOptions: {
show: {
operation: ['searchItems'],
},
},
default: '',
description: 'Keywords to search for items on Amazon',
},
{
displayName: 'Search Index (for Search Items)',
name: 'searchIndex',
type: 'options',
displayOptions: {
show: {
operation: ['searchItems'],
},
},
options: [
{ name: 'All', value: 'All' },
{ name: 'Apparel', value: 'Apparel' },
{ name: 'Automotive', value: 'Automotive' },
{ name: 'Baby', value: 'Baby' },
{ name: 'Beauty', value: 'Beauty' },
{ name: 'Books', value: 'Books' },
{ name: 'Electronics', value: 'Electronics' },
{ name: 'HomeAndKitchen', value: 'HomeAndKitchen' },
{ name: 'Music', value: 'Music' },
{ name: 'SportsAndOutdoors', value: 'SportsAndOutdoors' },
{ name: 'VideoGames', value: 'VideoGames' },
],
default: 'All',
description: 'Product category to search in',
},
{
displayName: 'Browse Node IDs (for Get Browse Nodes)',
name: 'browseNodeIds',
type: 'string',
displayOptions: {
show: {
operation: ['getBrowseNodes'],
},
},
default: '',
description: 'Comma-separated list of Browse Node IDs',
},
{
displayName: 'Resources',
name: 'resources',
type: 'multiOptions',
options: [
{ name: 'BrowseNodeInfo.BrowseNodes', value: 'BrowseNodeInfo.BrowseNodes' },
{ name: 'BrowseNodeInfo.WebsiteSalesRank', value: 'BrowseNodeInfo.WebsiteSalesRank' },
{ name: 'Images.Primary.Small', value: 'Images.Primary.Small' },
{ name: 'Images.Primary.Medium', value: 'Images.Primary.Medium' },
{ name: 'Images.Primary.Large', value: 'Images.Primary.Large' },
{ name: 'Images.Variants.Small', value: 'Images.Variants.Small' },
{ name: 'Images.Variants.Medium', value: 'Images.Variants.Medium' },
{ name: 'Images.Variants.Large', value: 'Images.Variants.Large' },
{ name: 'ItemInfo.ByLineInfo', value: 'ItemInfo.ByLineInfo' },
{ name: 'ItemInfo.ContentInfo', value: 'ItemInfo.ContentInfo' },
{ name: 'ItemInfo.ContentRating', value: 'ItemInfo.ContentRating' },
{ name: 'ItemInfo.Classifications', value: 'ItemInfo.Classifications' },
{ name: 'ItemInfo.ExternalIds', value: 'ItemInfo.ExternalIds' },
{ name: 'ItemInfo.Features', value: 'ItemInfo.Features' },
{ name: 'ItemInfo.ManufactureInfo', value: 'ItemInfo.ManufactureInfo' },
{ name: 'ItemInfo.ProductInfo', value: 'ItemInfo.ProductInfo' },
{ name: 'ItemInfo.TechnicalInfo', value: 'ItemInfo.TechnicalInfo' },
{ name: 'ItemInfo.Title', value: 'ItemInfo.Title' },
{ name: 'ItemInfo.TradeInInfo', value: 'ItemInfo.TradeInInfo' },
{ name: 'Offers.Listings.Availability.MaxOrderQuantity', value: 'Offers.Listings.Availability.MaxOrderQuantity' },
{ name: 'Offers.Listings.Availability.Message', value: 'Offers.Listings.Availability.Message' },
{ name: 'Offers.Listings.Availability.MinOrderQuantity', value: 'Offers.Listings.Availability.MinOrderQuantity' },
{ name: 'Offers.Listings.Availability.Type', value: 'Offers.Listings.Availability.Type' },
{ name: 'Offers.Listings.Condition', value: 'Offers.Listings.Condition' },
{ name: 'Offers.Listings.Condition.SubCondition', value: 'Offers.Listings.Condition.SubCondition' },
{ name: 'Offers.Listings.DeliveryInfo.IsAmazonFulfilled', value: 'Offers.Listings.DeliveryInfo.IsAmazonFulfilled' },
{ name: 'Offers.Listings.DeliveryInfo.IsFreeShippingEligible', value: 'Offers.Listings.DeliveryInfo.IsFreeShippingEligible' },
{ name: 'Offers.Listings.DeliveryInfo.IsPrimeEligible', value: 'Offers.Listings.DeliveryInfo.IsPrimeEligible' },
{ name: 'Offers.Listings.MerchantInfo', value: 'Offers.Listings.MerchantInfo' },
{ name: 'Offers.Listings.Price', value: 'Offers.Listings.Price' },
{ name: 'Offers.Listings.ProgramEligibility.IsPrimeExclusive', value: 'Offers.Listings.ProgramEligibility.IsPrimeExclusive' },
{ name: 'Offers.Listings.ProgramEligibility.IsPrimePantry', value: 'Offers.Listings.ProgramEligibility.IsPrimePantry' },
{ name: 'Offers.Listings.Promotions', value: 'Offers.Listings.Promotions' },
{ name: 'Offers.Listings.SavingBasis', value: 'Offers.Listings.SavingBasis' },
{ name: 'Offers.Summaries.HighestPrice', value: 'Offers.Summaries.HighestPrice' },
{ name: 'Offers.Summaries.LowestPrice', value: 'Offers.Summaries.LowestPrice' },
{ name: 'Offers.Summaries.OfferCount', value: 'Offers.Summaries.OfferCount' },
// New OffersV2 resources
{ name: 'OffersV2.Listings.DeliveryInfo.IsPrimeEligible', value: 'OffersV2.Listings.DeliveryInfo.IsPrimeEligible' },
{ name: 'OffersV2.Listings.Price', value: 'OffersV2.Listings.Price' },
{ name: 'OffersV2.Listings.SavingBasis', value: 'OffersV2.Listings.SavingBasis' },
],
default: [
'ItemInfo.Title',
'Offers.Listings.Price',
'Images.Primary.Medium',
],
description: 'Resources to include in the response',
},
{
displayName: 'Use OffersV2',
name: 'useOffersV2',
type: 'boolean',
default: false,
description: 'Whether to use the newer OffersV2 resource (requires API v1.2.2+)',
},
{
displayName: 'Additional Options',
name: 'additionalOptions',
type: 'collection',
placeholder: 'Add Option',
default: {},
options: [
{
displayName: 'Language of Preference',
name: 'languageOfPreference',
type: 'options',
options: [
{ name: 'Default', value: '' },
{ name: 'English', value: 'en_US' },
{ name: 'Spanish', value: 'es_US' },
{ name: 'French', value: 'fr_CA' },
{ name: 'German', value: 'de_DE' },
{ name: 'Italian', value: 'it_IT' },
{ name: 'Japanese', value: 'ja_JP' },
],
default: '',
description: 'Preferred language for item information',
},
{
displayName: 'Sort By (for Search Items)',
name: 'sortBy',
type: 'options',
displayOptions: {
show: {
'/operation': ['searchItems'],
},
},
options: [
{ name: 'Relevance', value: 'Relevance' },
{ name: 'Price: Low to High', value: 'PriceLowToHigh' },
{ name: 'Price: High to Low', value: 'PriceHighToLow' },
{ name: 'Average Customer Review', value: 'AvgCustomerReviews' },
{ name: 'Newest Arrivals', value: 'NewestArrivals' },
{ name: 'Featured', value: 'Featured' },
],
default: 'Relevance',
description: 'How to sort search results',
},
{
displayName: 'Item Page (for Search Items)',
name: 'itemPage',
type: 'number',
displayOptions: {
show: {
'/operation': ['searchItems'],
},
},
default: 1,
description: 'Page number of results (1-10)',
typeOptions: {
minValue: 1,
maxValue: 10,
},
},
{
displayName: 'Item Count (for Search Items)',
name: 'itemCount',
type: 'number',
displayOptions: {
show: {
'/operation': ['searchItems'],
},
},
default: 10,
description: 'Number of items per page (1-10)',
typeOptions: {
minValue: 1,
maxValue: 10,
},
},
{
displayName: 'Merchant (for Search Items)',
name: 'merchant',
type: 'options',
displayOptions: {
show: {
'/operation': ['searchItems'],
},
},
options: [
{ name: 'All', value: 'All' },
{ name: 'Amazon', value: 'Amazon' },
],
default: 'All',
description: 'Filter by merchant type',
},
{
displayName: 'Condition (for Search Items)',
name: 'condition',
type: 'options',
displayOptions: {
show: {
'/operation': ['searchItems'],
},
},
options: [
{ name: 'Any', value: 'Any' },
{ name: 'New', value: 'New' },
{ name: 'Used', value: 'Used' },
{ name: 'Collectible', value: 'Collectible' },
{ name: 'Refurbished', value: 'Refurbished' },
],
default: 'Any',
description: 'Filter by item condition',
},
{
displayName: 'Min Price (for Search Items)',
name: 'minPrice',
type: 'number',
displayOptions: {
show: {
'/operation': ['searchItems'],
},
},
default: 0,
description: 'Minimum price filter (in marketplace currency)',
typeOptions: {
minValue: 0,
},
},
{
displayName: 'Max Price (for Search Items)',
name: 'maxPrice',
type: 'number',
displayOptions: {
show: {
'/operation': ['searchItems'],
},
},
default: 0,
description: 'Maximum price filter (0 = no maximum, in marketplace currency)',
typeOptions: {
minValue: 0,
},
},
{
displayName: 'Min Reviews (for Search Items)',
name: 'minReviewsRating',
type: 'number',
displayOptions: {
show: {
'/operation': ['searchItems'],
},
},
default: 0,
description: 'Minimum customer review rating (1-5)',
typeOptions: {
minValue: 0,
maxValue: 5,
},
},
],
},
],
};
}
async execute() {
var _a, _b, _c, _d, _e;
const items = this.getInputData();
const returnData = [];
// Retrieve credentials
const credentials = await this.getCredentials('amazonPaApi');
// Get partnerTag either from the input or from the credentials
const partnerTag = this.getNodeParameter('partnerTag', 0, '') || credentials.partnerTag;
// Ensure PartnerTag exists
if (!partnerTag) {
throw new Error('PartnerTag is required but was not provided in both the request and credentials.');
}
const commonParameters = {
AccessKey: credentials.accessKey,
SecretKey: credentials.secretKey,
PartnerTag: partnerTag,
Marketplace: credentials.marketplace,
PartnerType: 'Associates',
};
// Loop through each item
for (let i = 0; i < items.length; i++) {
let responseData;
const requestParameters = {};
try {
const operation = this.getNodeParameter('operation', i);
const resources = this.getNodeParameter('resources', i, []);
// Add any additional parameters
const additionalOptions = this.getNodeParameter('additionalOptions', i, {});
// Add language preference if specified
if (additionalOptions.languageOfPreference) {
requestParameters.LanguageOfPreference = additionalOptions.languageOfPreference;
}
// Set resources for all operations
requestParameters.Resources = resources;
// Check if we should use OffersV2
const useOffersV2 = this.getNodeParameter('useOffersV2', i, false);
// Update resources to use OffersV2 if selected
if (useOffersV2) {
// Replace any Offers resources with OffersV2
requestParameters.Resources = requestParameters.Resources.map((resource) => {
if (resource.startsWith('Offers.')) {
return resource.replace('Offers.', 'OffersV2.');
}
return resource;
});
}
if (operation === 'getItems') {
// Handling Get Items request
const itemIds = this.getNodeParameter('itemIds', i);
if (itemIds) {
requestParameters.ItemIds = itemIds.includes(',') ? itemIds.split(',').map(id => id.trim()) : [itemIds.trim()];
}
else {
throw new Error('Item IDs are required but were not provided.');
}
const getItemsParams = {
ItemIds: requestParameters.ItemIds,
Resources: requestParameters.Resources,
};
if (requestParameters.LanguageOfPreference) {
getItemsParams.LanguageOfPreference = requestParameters.LanguageOfPreference;
}
responseData = await amazonPaapi.GetItems(commonParameters, getItemsParams);
}
else if (operation === 'searchItems') {
// Handling Search Items request
const keywords = this.getNodeParameter('keywords', i);
const searchIndex = this.getNodeParameter('searchIndex', i, 'All');
requestParameters.Keywords = keywords;
requestParameters.SearchIndex = searchIndex;
// Add optional search parameters
if (additionalOptions.sortBy) {
requestParameters.SortBy = additionalOptions.sortBy;
}
if (additionalOptions.itemPage) {
requestParameters.ItemPage = additionalOptions.itemPage;
}
if (additionalOptions.itemCount) {
requestParameters.ItemCount = additionalOptions.itemCount;
}
if (additionalOptions.merchant) {
requestParameters.Merchant = additionalOptions.merchant;
}
if (additionalOptions.condition) {
requestParameters.Condition = additionalOptions.condition;
}
// Add min/max price if specified
if (((_a = additionalOptions.minPrice) !== null && _a !== void 0 ? _a : 0) > 0 || ((_b = additionalOptions.maxPrice) !== null && _b !== void 0 ? _b : 0) > 0) {
requestParameters.MinPrice = ((_c = additionalOptions.minPrice) !== null && _c !== void 0 ? _c : 0) > 0 ? additionalOptions.minPrice : undefined;
requestParameters.MaxPrice = ((_d = additionalOptions.maxPrice) !== null && _d !== void 0 ? _d : 0) > 0 ? additionalOptions.maxPrice : undefined;
}
// Add min review rating if specified
if (((_e = additionalOptions.minReviewsRating) !== null && _e !== void 0 ? _e : 0) > 0) {
requestParameters.MinReviewsRating = additionalOptions.minReviewsRating;
}
const searchItemsParams = {
Keywords: keywords,
Resources: requestParameters.Resources,
SearchIndex: searchIndex,
};
// Add optional parameters
if (requestParameters.LanguageOfPreference) {
searchItemsParams.LanguageOfPreference = requestParameters.LanguageOfPreference;
}
if (requestParameters.SortBy) {
searchItemsParams.SortBy = requestParameters.SortBy;
}
if (requestParameters.ItemPage) {
searchItemsParams.ItemPage = requestParameters.ItemPage;
}
if (requestParameters.ItemCount) {
searchItemsParams.ItemCount = requestParameters.ItemCount;
}
if (requestParameters.Merchant) {
searchItemsParams.Merchant = requestParameters.Merchant;
}
if (requestParameters.Condition) {
searchItemsParams.Condition = requestParameters.Condition;
}
if (requestParameters.MinPrice) {
searchItemsParams.MinPrice = requestParameters.MinPrice;
}
if (requestParameters.MaxPrice) {
searchItemsParams.MaxPrice = requestParameters.MaxPrice;
}
if (requestParameters.MinReviewsRating) {
searchItemsParams.MinReviewsRating = requestParameters.MinReviewsRating;
}
responseData = await amazonPaapi.SearchItems(commonParameters, searchItemsParams);
}
else if (operation === 'getBrowseNodes') {
// Handling Get Browse Nodes request
const browseNodeIds = this.getNodeParameter('browseNodeIds', i);
if (browseNodeIds) {
requestParameters.BrowseNodeIds = browseNodeIds.includes(',') ? browseNodeIds.split(',').map(id => id.trim()) : [browseNodeIds.trim()];
}
else {
throw new Error('Browse Node IDs are required but were not provided.');
}
const getBrowseNodesParams = {
BrowseNodeIds: requestParameters.BrowseNodeIds,
Resources: requestParameters.Resources,
};
if (requestParameters.LanguageOfPreference) {
getBrowseNodesParams.LanguageOfPreference = requestParameters.LanguageOfPreference;
}
responseData = await amazonPaapi.GetBrowseNodes(commonParameters, getBrowseNodesParams);
}
else if (operation === 'getVariations') {
// Handling Get Variations request
const variationAsin = this.getNodeParameter('variationAsin', i);
if (!variationAsin) {
throw new Error('ASIN is required for Get Variations operation.');
}
requestParameters.ASIN = variationAsin;
const getVariationsParams = {
ASIN: variationAsin,
Resources: requestParameters.Resources,
};
if (requestParameters.LanguageOfPreference) {
getVariationsParams.LanguageOfPreference = requestParameters.LanguageOfPreference;
}
responseData = await amazonPaapi.GetVariations(commonParameters, getVariationsParams);
}
// Process the response data to make it more user-friendly
let processedData = {};
// Check if we have error elements in the response
if (responseData === null || responseData === void 0 ? void 0 : responseData.Errors) {
console.error('Amazon PA API Error:', JSON.stringify(responseData.Errors, null, 2));
// Create a user-friendly error message for the output
const errorMessages = responseData.Errors.map((error) => `Code: ${error.Code}, Message: ${error.Message}`).join('; ');
processedData = {
success: false,
errors: responseData.Errors,
errorMessage: errorMessages,
originalResponse: responseData,
};
}
else {
// Add a success flag for easier checking
processedData = {
success: true,
...responseData,
};
}
// Add response to returnData
returnData.push({ json: processedData });
}
catch (error) {
console.error('Amazon PA API Request Error:', error);
// Create a structured error response
const errorResponse = {
success: false,
errorMessage: error instanceof Error ? error.message : 'Unknown error occurred',
errorDetail: error instanceof Error ? error.stack : undefined,
};
returnData.push({ json: errorResponse });
}
}
// Return the processed data
return [returnData];
}
}
exports.AmazonPA = AmazonPA;