Product Catalog Access

Access and explore comprehensive travel product catalogs with advanced filtering, search, and information retrieval capabilities using the Products V2 API.

Overview

Product catalog access involves exploring and retrieving information from comprehensive collections of travel products. The Products V2 API provides powerful tools for accessing sophisticated product catalogs with advanced filtering, search, and information retrieval capabilities.

Key Features

  • Product Information Access: Access products with rich metadata
  • Advanced Filtering: Filter products by multiple criteria
  • Search Capabilities: Find products quickly and efficiently
  • Bulk Data Retrieval: Access multiple products simultaneously
  • Variant Information: Access product variants and consolidations
  • Status Information: View product availability and visibility

Implementation Examples

1. Accessing a Product Catalog

Access a comprehensive product catalog with multiple product types:

Access
class ProductCatalogAccessor {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = 'https://api.joinsherpa.io/v2/products';
  }

  // Get products for a specific destination
  async getDestinationCatalog(destination, filters = {}) {
    const params = new URLSearchParams({
      destination,
      status: 'ACTIVE',
      ...filters
    });
    
    const response = await fetch(`${this.baseUrl}?${params}`, {
      method: 'GET',
      headers: {
        'x-api-key': `${this.apiKey}`,
      },
    });

    if (!response.ok) {
      const errorData = await response.json();
      throw new Error(`API Error: ${errorData.message}`);
    }

    return await response.json();
  }

  // Get products with advanced filtering
  async getProducts(filters = {}) {
    const params = new URLSearchParams();
    Object.entries(filters).forEach(([key, value]) => {
      if (value !== undefined && value !== null) {
        params.append(key, value);
      }
    });

    const response = await fetch(`${this.baseUrl}?${params}`, {
      headers: {
        'x-api-key': `${this.apiKey}`,
      },
    });

    if (!response.ok) {
      const errorData = await response.json();
      throw new Error(`API Error: ${errorData.message}`);
    }

    return await response.json();
  }

  // Get a specific product by ID
  async getProductById(productId) {
    const response = await fetch(`${this.baseUrl}/${productId}`, {
      method: 'GET',
      headers: {
        'x-api-key': `${this.apiKey}`,
      },
    });

    if (!response.ok) {
      const errorData = await response.json();
      throw new Error(`API Error: ${errorData.message}`);
    }

    return await response.json();
  }
}

// Usage example
const catalogAccessor = new ProductCatalogAccessor('YOUR_API_KEY');

// Get Turkey product catalog
catalogAccessor.getDestinationCatalog('TUR', { currency: 'USD' })
  .then(products => {
    console.log('Turkey products:', products);
  })
  .catch(error => {
    console.error('Error accessing catalog:', error);
  });

2. Advanced Product Filtering

Use sophisticated filtering for product discovery:

Advanced
class ProductFilter {
  constructor(catalogAccessor) {
    this.catalogAccessor = catalogAccessor;
  }

  // Filter products by destination and nationality
  async getProductsForTravel(destination, nationality, options = {}) {
    const filters = {
      destination,
      nationality,
      status: 'ACTIVE',
      currency: options.currency || 'USD',
      ...options
    };

    return await this.catalogAccessor.getProducts(filters);
  }

  // Filter products by travel purpose
  async getProductsByPurpose(travelPurpose, options = {}) {
    const filters = {
      travelPurpose,
      status: 'ACTIVE',
      currency: options.currency || 'USD',
      ...options
    };

    return await this.catalogAccessor.getProducts(filters);
  }

  // Filter products by price range
  async getProductsByPriceRange(minPrice, maxPrice, options = {}) {
    const allProducts = await this.catalogAccessor.getProducts({
      status: 'ACTIVE',
      currency: options.currency || 'USD',
      ...options
    });

    return allProducts.filter(product => {
      const price = product.pricing?.price || 0;
      return price >= minPrice && price <= maxPrice;
    });
  }

  // Filter products by processing time
  async getProductsByProcessingTime(maxHours, options = {}) {
    const allProducts = await this.catalogAccessor.getProducts({
      status: 'ACTIVE',
      currency: options.currency || 'USD',
      ...options
    });

    return allProducts.filter(product => {
      const processingTime = product.processingTime;
      if (!processingTime) return false;
      
      const hours = processingTime.unit === 'HOURS' ? processingTime.value :
                   processingTime.unit === 'DAYS' ? processingTime.value * 24 :
                   processingTime.unit === 'MINUTES' ? processingTime.value / 60 : 0;
      
      return hours <= maxHours;
    });
  }

  // Get consolidated products (one per destination)
  async getConsolidatedProducts(options = {}) {
    const filters = {
      consolidateProducts: true,
      status: 'ACTIVE',
      currency: options.currency || 'USD',
      ...options
    };

    return await this.catalogAccessor.getProducts(filters);
  }
}

// Usage examples
const productFilter = new ProductFilter(catalogAccessor);

// Get products for US citizens traveling to Turkey
productFilter.getProductsForTravel('TUR', 'USA')
  .then(products => {
    console.log('Turkey products for US citizens:', products);
  });

// Get tourism products
productFilter.getProductsByPurpose('TOURISM')
  .then(products => {
    console.log('Tourism products:', products);
  });

// Get products under $100
productFilter.getProductsByPriceRange(0, 100)
  .then(products => {
    console.log('Products under $100:', products);
  });

// Get products with 24-hour processing
productFilter.getProductsByProcessingTime(24)
  .then(products => {
    console.log('Fast processing products:', products);
  });

3. Bulk Product Information Access

Access multiple products efficiently:

Bulk
class BulkProductAccessor {
  constructor(catalogAccessor) {
    this.catalogAccessor = catalogAccessor;
  }

  // Get multiple products by IDs
  async getMultipleProducts(productIds) {
    const results = [];
    
    for (const productId of productIds) {
      try {
        const product = await this.catalogAccessor.getProductById(productId);
        results.push({ success: true, productId, product });
      } catch (error) {
        results.push({ success: false, productId, error: error.message });
      }
    }
    
    return results;
  }

  // Get products by multiple destinations
  async getProductsByDestinations(destinations, options = {}) {
    const results = [];
    
    for (const destination of destinations) {
      try {
        const products = await this.catalogAccessor.getDestinationCatalog(destination, options);
        results.push({ success: true, destination, products });
      } catch (error) {
        results.push({ success: false, destination, error: error.message });
      }
    }
    
    return results;
  }

  // Get products by multiple nationalities
  async getProductsByNationalities(nationalities, options = {}) {
    const results = [];
    
    for (const nationality of nationalities) {
      try {
        const products = await this.catalogAccessor.getProducts({
          nationality,
          status: 'ACTIVE',
          ...options
        });
        results.push({ success: true, nationality, products });
      } catch (error) {
        results.push({ success: false, nationality, error: error.message });
      }
    }
    
    return results;
  }
}

// Usage examples
const bulkAccessor = new BulkProductAccessor(catalogAccessor);

// Get multiple products by IDs
bulkAccessor.getMultipleProducts(['product-1', 'product-2', 'product-3'])
  .then(results => {
    console.log('Multiple products results:', results);
  });

// Get products for multiple destinations
bulkAccessor.getProductsByDestinations(['TUR', 'EGY', 'IND'], { currency: 'USD' })
  .then(results => {
    console.log('Multi-destination products:', results);
  });

4. Product Search and Discovery

Use powerful search capabilities:

Product
class ProductSearch {
  constructor(catalogAccessor) {
    this.catalogAccessor = catalogAccessor;
  }

  // Search products by name or description
  async searchProducts(query, options = {}) {
    const allProducts = await this.catalogAccessor.getProducts({
      status: 'ACTIVE',
      currency: options.currency || 'USD',
      ...options
    });

    const searchTerm = query.toLowerCase();
    
    return allProducts.filter(product => {
      const name = (product.name || '').toLowerCase();
      const description = (product.description || '').toLowerCase();
      const shortDescription = (product.shortDescription || '').toLowerCase();
      
      return name.includes(searchTerm) || 
             description.includes(searchTerm) || 
             shortDescription.includes(searchTerm);
    });
  }

  // Find products by destination name
  async findProductsByDestination(destinationName, options = {}) {
    const allProducts = await this.catalogAccessor.getProducts({
      status: 'ACTIVE',
      currency: options.currency || 'USD',
      ...options
    });

    const searchTerm = destinationName.toLowerCase();
    
    return allProducts.filter(product => {
      return product.destinations?.some(dest => 
        dest.label?.toLowerCase().includes(searchTerm) ||
        dest.value?.toLowerCase().includes(searchTerm)
      );
    });
  }

  // Find products by nationality
  async findProductsByNationality(nationalityName, options = {}) {
    const allProducts = await this.catalogAccessor.getProducts({
      status: 'ACTIVE',
      currency: options.currency || 'USD',
      ...options
    });

    const searchTerm = nationalityName.toLowerCase();
    
    return allProducts.filter(product => {
      return product.eligibleNationalities?.some(nat => 
        nat.label?.toLowerCase().includes(searchTerm) ||
        nat.value?.toLowerCase().includes(searchTerm)
      );
    });
  }

  // Get product recommendations
  async getProductRecommendations(destination, nationality, options = {}) {
    const products = await this.catalogAccessor.getProducts({
      destination,
      nationality,
      status: 'ACTIVE',
      currency: options.currency || 'USD',
      ...options
    });

    // Sort by popularity, price, or processing time
    return products.sort((a, b) => {
      if (options.sortBy === 'price') {
        return (a.pricing?.price || 0) - (b.pricing?.price || 0);
      } else if (options.sortBy === 'processingTime') {
        const aTime = this.getProcessingTimeInHours(a.processingTime);
        const bTime = this.getProcessingTimeInHours(b.processingTime);
        return aTime - bTime;
      } else {
        // Default sort by name
        return (a.name || '').localeCompare(b.name || '');
      }
    });
  }

  getProcessingTimeInHours(processingTime) {
    if (!processingTime) return 0;
    
    switch (processingTime.unit) {
      case 'HOURS': return processingTime.value;
      case 'DAYS': return processingTime.value * 24;
      case 'MINUTES': return processingTime.value / 60;
      default: return 0;
    }
  }
}

// Usage examples
const productSearch = new ProductSearch(catalogAccessor);

// Search for Turkey products
productSearch.searchProducts('Turkey')
  .then(products => {
    console.log('Turkey search results:', products);
  });

// Find products for US citizens
productSearch.findProductsByNationality('United States')
  .then(products => {
    console.log('Products for US citizens:', products);
  });

// Get product recommendations
productSearch.getProductRecommendations('TUR', 'USA', { sortBy: 'price' })
  .then(products => {
    console.log('Recommended products:', products);
  });

Best Practices

Product Organization

  • Consistent Naming: Use consistent naming conventions for product IDs
  • Logical Grouping: Group related products by destination or type
  • Clear Descriptions: Provide clear, descriptive product information
  • Proper Categorization: Use appropriate product types and subtypes

Performance Optimization

  • Caching: Implement caching for frequently accessed products
  • Pagination: Use pagination for large product catalogs
  • Filtering: Use specific filters to reduce response size
  • Batch Operations: Use bulk operations for multiple product access

Error Handling

  • Validation: Validate request parameters before API calls
  • Retry Logic: Implement retry logic for transient errors
  • Error Logging: Log errors for debugging and monitoring
  • Graceful Degradation: Handle errors gracefully in user interfaces

Data Management

  • Backup: Regularly backup product data
  • Data Integrity: Ensure consistent data access patterns
  • Monitoring: Monitor product catalog health and performance
💡 Catalog Tips
  • Use product variants for different travel purposes to the same destination
  • Implement search functionality for better product discovery
  • Use bulk operations for efficient catalog management
  • Monitor product performance and user engagement
🚀 Getting Started

Start with a small product catalog and gradually expand. Use the quickstart guide to create your first products and build from there.