# Element14 Product Search Api > The Element14 Product Search API is a RESTful web service provided by Avnet that enables programmatic access to product catalogs across Element14, Newark, and Farnell electronic component distributors --- # Element14 Product Search API - Overview The Element14 Product Search API is a RESTful web service provided by Avnet that enables programmatic access to product catalogs across Element14, Newark, and Farnell electronic component distributors. This shared API allows developers to search for electronic components, retrieve detailed product information, pricing, and inventory data. ## Supported Distributors The API covers three regional distribution platforms under Avnet ownership: - **Element14** - Global electronics distributor - **Newark** - North American distributor - **Farnell** - European distributor Each platform maintains its own regional catalog and pricing, accessible through store IDs in the API. ## API Versions The current API supports multiple versions (1.1 through 1.4) with updates to improve functionality and data structure. ## Key Features - **Product Search**: Keyword search across component catalogs - **Part Number Lookup**: Direct searches by product ID or manufacturer part number - **Multi-Format Output**: XML or JSON response formats - **Regional Support**: 40+ regional store configurations - **Flexible Response Groups**: Customize payload size based on use case - **Pricing Data**: Standard and contract pricing tiers available - **Stock Information**: Real-time inventory by warehouse - **Images & Metadata**: Product images and related product recommendations ## Authentication Tiers ### Standard Pricing - Uses 24-character alphanumeric API key - Basic pricing tier access - Suitable for most product searches ### Contract Pricing - Requires additional authentication parameters - HMAC-SHA1 signature-based authentication - Customer ID and timestamp required - Provides negotiated pricing for volume customers ## Documentation Resources - **Developer Portal**: https://partner.element14.com/docs - **API Gallery**: https://partner.element14.com/api_gallery - **Python Wrapper**: https://pyfarnell.readthedocs.io/ ## Use Cases The API enables integration with various enterprise systems: - Electronics design tools (PCB CAD software) - BOM management systems - ERP and quote management platforms - Real-time pricing and inventory lookup - Component discovery for design workflows - Automated purchasing workflows ## Getting Started To use the Element14 Product Search API: 1. Register at the Element14 Partner Portal (https://partner.element14.com/) 2. Request API credentials from your account 3. Obtain a 24-character alphanumeric API key 4. Select your target regional store (Element14, Newark, or Farnell) 5. Construct API requests using the REST endpoint 6. Parse XML or JSON responses based on your requirements --- # Authentication The Element14 Product Search API supports two authentication models depending on your pricing tier and requirements. ## Standard Authentication Standard tier uses a simple API key-based authentication: ### API Key Format - 24-character alphanumeric string - Provided by Element14 Partner Portal - Included in every API request ### How to Obtain 1. Create an account at https://partner.element14.com/ 2. Log in to your account dashboard 3. Navigate to API settings or credentials section 4. Generate or retrieve your 24-character API key 5. Store securely (treat like a password) ### Usage in Requests Include the API key in the `callInfo.apiKey` parameter: ``` https://api.element14.com/catalog/products?callInfo.apiKey=YOUR_24_CHAR_KEY&... ``` ## Contract Pricing Authentication Contract pricing provides negotiated bulk pricing but requires additional authentication mechanisms. ### Required Parameters Beyond the standard API key, contract pricing requires: - `userInfo.signature` - HMAC-SHA1 signature of the request - `userInfo.timestamp` - ISO 8601 formatted timestamp - `userInfo.customerId` - Your contract customer ID ### Signature Generation The signature is an HMAC-SHA1 hash of the operation name and timestamp: **Steps:** 1. Format timestamp in ISO 8601 format (e.g., `2024-01-08T14:30:00Z`) 2. Concatenate operation name with timestamp (e.g., `searchAPI2024-01-08T14:30:00Z`) 3. Generate HMAC-SHA1 hash using your contract API key as the secret 4. URL-encode the resulting signature 5. Include in `userInfo.signature` parameter **PHP Example:** ```php $timestamp = date('c'); // ISO 8601 format $operation = 'searchAPI'; $message = $operation . $timestamp; $signature = hash_hmac('sha1', $message, $apiKey, false); $signatureUrlEncoded = rawurlencode($signature); ``` **Python Example:** ```python import hmac import hashlib from datetime import datetime from urllib.parse import quote timestamp = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ') operation = 'searchAPI' message = f'{operation}{timestamp}' signature = hmac.new( api_key.encode(), message.encode(), hashlib.sha1 ).hexdigest() signature_encoded = quote(signature, safe='') ``` ### Contract Pricing Request Example ``` GET https://api.element14.com/catalog/products ?term=any:capacitor &storeInfo.id=40 &callInfo.apiKey=YOUR_24_CHAR_KEY &userInfo.signature=HMAC_SIGNATURE &userInfo.timestamp=2024-01-08T14:30:00Z &userInfo.customerId=YOUR_CONTRACT_ID &callInfo.responseDataFormat=json ``` ## Security Considerations - Treat API keys as secrets - never commit to version control - Use HTTPS for all requests (mandatory) - Regenerate API keys periodically - Use environment variables or secure credential stores - For server-side integrations, restrict API key usage by IP if possible - Contract pricing signatures include timestamps to prevent replay attacks ## Rate Limiting The documentation does not publicly specify rate limits. Contact Element14 support for: - Rate limits on standard tier - Rate limits on contract tier - Burst capacity and throttling parameters - Dedicated endpoint availability for high-volume usage --- # API Endpoints ## Base Endpoint ``` https://api.element14.com/catalog/products ``` All requests use the HTTP GET method to this single endpoint. The endpoint behavior is controlled entirely through query parameters. ## Request Structure ``` https://api.element14.com/catalog/products?param1=value1¶m2=value2&... ``` ## Regional Store Identifiers The `storeInfo.id` parameter specifies which regional catalog and pricing to query. Available stores include 40+ regional options: **Major Regional Stores:** - **40** - Element14 (Japan) - **41** - Farnell (UK) - **43** - Newark (US) - **44** - Farnell (UK/Europe) - **45** - Element14 (Australia) - **46** - Element14 (Singapore) - **47** - Element14 (Malaysia) - **48** - Farnell (Germany) - **49** - Farnell (Netherlands) - **50** - Farnell (France) - **51** - Farnell (Spain) - **52** - Farnell (Italy) - **53** - Element14 (China) - **54** - Element14 (Hong Kong) - **55** - Element14 (Taiwan) - **56** - Element14 (Korea) - **57** - Element14 (India) - **59** - Element14 (New Zealand) - **70** - Farnell (Poland) - **72** - Element14 (Brazil) - **74** - Element14 (Mexico) - **75** - Farnell (Austria) - **76** - Farnell (Belgium) - **77** - Farnell (Czech Republic) - **78** - Element14 (Hungary) - **79** - Farnell (Portugal) - **80** - Element14 (Israel) - **81** - Farnell (Romania) - **82** - Element14 (Saudi Arabia) - **83** - Element14 (Pakistan) - **84** - Farnell (Ireland) - **85** - Farnell (Greece) - **88** - Element14 (Russia/CIS) - **89** - Farnell (Denmark) - **91** - Farnell (Sweden) - **92** - Element14 (Bulgaria) - **94** - Farnell (Finland) - **97** - Element14 (Turkey) ## Query Parameters ### Required Parameters **`term`** - Search query (required) - Keyword search: `any:search term` - Product ID search: `id:element14_part_number` - Manufacturer part number: `manuPartNum:MPN` Examples: ``` term=any:resistor 10k term=any:microcontroller STM32 term=id:8947381 term=manuPartNum:IMXRT1060IEC ``` **`storeInfo.id`** - Regional store ID (required) ``` storeInfo.id=43 ``` **`callInfo.apiKey`** - API authentication key (required for standard tier) ``` callInfo.apiKey=YOUR_24_CHAR_KEY ``` ### Response Format Parameters **`callInfo.responseDataFormat`** - Output format - `xml` - XML format (default) - `json` - JSON format **`resultsSettings.responseGroup`** - Response detail level - `small` - Minimal product info (part number, description, category) - `medium` - Includes pricing and stock (default) - `large` - Includes images and related products - `prices` - Pricing tier information only - `inventory` - Stock breakdown by warehouse/location - `none` - Result count only ### Pagination Parameters **`resultsSettings.pageSize`** - Results per page - Default: 10 - Maximum: typically 100 (confirm with support) **`resultsSettings.pageNumber`** - Page number for pagination - Default: 1 - Start: 1 (not 0-indexed) ### Filtering Parameters **`resultsSettings.refinements`** - Apply filters to search results - Can filter by category, price range, stock status - Format: `refinements=parameter:value` ## Complete Example Request **Keyword Search - JSON Format:** ``` https://api.element14.com/catalog/products ?term=any:resistor &storeInfo.id=43 &callInfo.apiKey=ABCD1234EFGH5678IJKL9012MN &callInfo.responseDataFormat=json &resultsSettings.responseGroup=medium &resultsSettings.pageSize=20 ``` **Manufacturer Part Number Search - XML Format:** ``` https://api.element14.com/catalog/products ?term=manuPartNum:LM7805CT &storeInfo.id=41 &callInfo.apiKey=ABCD1234EFGH5678IJKL9012MN &callInfo.responseDataFormat=xml &resultsSettings.responseGroup=large ``` **Product ID Search:** ``` https://api.element14.com/catalog/products ?term=id:4298467 &storeInfo.id=45 &callInfo.apiKey=ABCD1234EFGH5678IJKL9012MN &callInfo.responseDataFormat=json &resultsSettings.responseGroup=prices ``` ## URL Encoding All special characters in parameters must be URL-encoded: - Space → `%20` or `+` - `&` → `%26` - `=` → `%3D` - `:` → `%3A` (in some contexts) Most HTTP client libraries handle this automatically. ## Contract Pricing Endpoint Usage The same endpoint supports contract pricing with additional parameters: ``` https://api.element14.com/catalog/products ?term=any:component &storeInfo.id=43 &callInfo.apiKey=STANDARD_KEY &userInfo.signature=HMAC_SIGNATURE &userInfo.timestamp=2024-01-08T14:30:00Z &userInfo.customerId=CONTRACT_ID123 &callInfo.responseDataFormat=json ``` See the Authentication section for signature generation details. --- # Response Formats The Element14 Product Search API returns data in either XML or JSON format, specified via the `callInfo.responseDataFormat` parameter. ## JSON Response Format JSON format is preferred for modern applications and REST integrations. ### Response Structure ```json { "response": { "statusCode": 200, "statusMessage": "OK", "numFound": 1250, "totalPages": 63, "currentPage": 1, "pageSize": 20, "products": [ { "sku": "8947381", "description": "10kΩ Carbon Film Resistor 1/4W 5%", "partNumber": "CF14JT10K0", "manufacturerPartNumber": "CF14JT10K0", "manufacturer": "Yageo", "productFamily": "Carbon Film Resistors", "category": "Resistors > Thick Film / Carbon Resistors > Carbon Film", "unitPrice": 0.0275, "currencyCode": "USD", "stockLevel": 15420, "minimumOrderQty": 1, "orderMultiple": 1, "images": [ { "url": "https://api.element14.com/images/CF14JT10K0_40_200.jpg", "size": "large" } ], "datasheetUrl": "https://...", "specifications": { "resistance": "10kΩ", "tolerance": "5%", "power": "0.25W", "temperature": "-55°C to +125°C" } } ] } } ``` ### JSON Response Fields **Response Metadata:** - `statusCode` - HTTP status code - `statusMessage` - Status description - `numFound` - Total results matching query - `totalPages` - Total number of pages - `currentPage` - Current page number - `pageSize` - Results per page **Product Fields:** - `sku` - Stock keeping unit (Element14 internal ID) - `description` - Product description - `partNumber` - Element14/Newark/Farnell part number - `manufacturerPartNumber` - Manufacturer's part number - `manufacturer` - Manufacturer name - `productFamily` - Product line/family - `category` - Product category hierarchy - `unitPrice` - Price per unit - `currencyCode` - Currency (USD, GBP, EUR, etc.) - `stockLevel` - Available quantity - `minimumOrderQty` - Minimum purchase quantity - `orderMultiple` - Must order in multiples of this - `images` - Product images array - `datasheetUrl` - Link to datasheet PDF - `specifications` - Key technical specifications ### Response Groups - JSON Different response groups return different field sets: **`responseGroup=small`** ```json { "sku": "8947381", "description": "10kΩ Carbon Film Resistor", "partNumber": "CF14JT10K0", "manufacturer": "Yageo" } ``` **`responseGroup=medium` (default)** ```json { "sku": "8947381", "description": "10kΩ Carbon Film Resistor", "partNumber": "CF14JT10K0", "manufacturer": "Yageo", "unitPrice": 0.0275, "currencyCode": "USD", "stockLevel": 15420, "minimumOrderQty": 1 } ``` **`responseGroup=large`** ```json { "sku": "8947381", "description": "10kΩ Carbon Film Resistor", "partNumber": "CF14JT10K0", "manufacturer": "Yageo", "unitPrice": 0.0275, "currencyCode": "USD", "stockLevel": 15420, "images": [...], "specifications": {...}, "relatedProducts": [...], "distributorInventory": [...] } ``` **`responseGroup=prices`** ```json { "sku": "8947381", "partNumber": "CF14JT10K0", "pricingTiers": [ {"minQty": 1, "price": 0.0275}, {"minQty": 100, "price": 0.0215}, {"minQty": 1000, "price": 0.0175} ], "currencyCode": "USD" } ``` **`responseGroup=inventory`** ```json { "sku": "8947381", "partNumber": "CF14JT10K0", "warehouseInventory": [ { "location": "New Jersey", "quantity": 8500 }, { "location": "Chicago", "quantity": 6920 } ] } ``` **`responseGroup=none`** ```json { "response": { "statusCode": 200, "numFound": 1250, "currentPage": 1, "products": [] } } ``` ## XML Response Format XML format for legacy system integration. ### Response Structure ```xml 200 OK 1250 63 1 20 8947381 10kΩ Carbon Film Resistor 1/4W 5% CF14JT10K0 CF14JT10K0 Yageo Carbon Film Resistors Resistors > Thick Film / Carbon Resistors > Carbon Film 0.0275 USD 15420 1 1 https://api.element14.com/images/CF14JT10K0_40_200.jpg https://... 10kΩ 5% 0.25W -55°C to +125°C ``` ## Error Responses ### Invalid Request - JSON ```json { "response": { "statusCode": 400, "statusMessage": "Bad Request", "errorMessage": "Invalid API key provided" } } ``` ### Common Error Codes - **200** - Success - **400** - Bad request (invalid parameters) - **401** - Unauthorized (invalid API key) - **403** - Forbidden (insufficient permissions) - **404** - Not found (no results) - **429** - Rate limit exceeded - **500** - Server error ### Error Messages Common error conditions: ```json { "statusCode": 400, "errorMessage": "Search term is required" } ``` ```json { "statusCode": 401, "errorMessage": "Invalid API key" } ``` ```json { "statusCode": 404, "errorMessage": "No results found for the given search term" } ``` ## Pagination ### Navigating Results Results are paginated. To retrieve multiple pages: 1. Set `resultsSettings.pageSize` to desired page size (default 10, max ~100) 2. Use `resultsSettings.pageNumber` to request subsequent pages 3. Check `totalPages` in response to know how many pages exist 4. Iterate from `pageNumber=1` to `pageNumber=totalPages` ### Pagination Example First request: ``` ?term=any:resistor&resultsSettings.pageSize=20&resultsSettings.pageNumber=1 ``` Response includes: ```json { "numFound": 1250, "totalPages": 63, "currentPage": 1, "pageSize": 20 } ``` Second request (page 2): ``` ?term=any:resistor&resultsSettings.pageSize=20&resultsSettings.pageNumber=2 ``` ## Image URLs Product images are provided in the response when using `responseGroup=large` or larger: ```json { "images": [ { "url": "https://api.element14.com/images/CF14JT10K0_40_200.jpg", "size": "large" }, { "url": "https://api.element14.com/images/CF14JT10K0_40_50.jpg", "size": "small" } ] } ``` Image URL patterns follow Element14's image hosting CDN. ## Datasheet URLs Datasheet links are available in responses: ```json { "datasheetUrl": "https://api.element14.com/datasheets/yageo_cf14jt10k0_datasheet.pdf" } ``` These URLs typically redirect to the manufacturer's official datasheet on Element14's system. --- # Code Examples ## Python Examples ### Basic Keyword Search ```python import requests import json API_KEY = "YOUR_24_CHAR_KEY" BASE_URL = "https://api.element14.com/catalog/products" def search_products(search_term, store_id=43, page=1): """Search for products by keyword""" params = { 'term': f'any:{search_term}', 'storeInfo.id': store_id, 'callInfo.apiKey': API_KEY, 'callInfo.responseDataFormat': 'json', 'resultsSettings.responseGroup': 'medium', 'resultsSettings.pageNumber': page, 'resultsSettings.pageSize': 20 } response = requests.get(BASE_URL, params=params) response.raise_for_status() return response.json() # Search for resistors result = search_products('resistor 10k') print(f"Found {result['response']['numFound']} products") for product in result['response']['products']: print(f"{product['partNumber']}: {product['description']}") print(f" Price: ${product['unitPrice']}") print(f" Stock: {product['stockLevel']}\n") ``` ### Search by Manufacturer Part Number ```python def search_by_mfn(mfn, store_id=43): """Search by manufacturer part number""" params = { 'term': f'manuPartNum:{mfn}', 'storeInfo.id': store_id, 'callInfo.apiKey': API_KEY, 'callInfo.responseDataFormat': 'json', 'resultsSettings.responseGroup': 'large' } response = requests.get(BASE_URL, params=params) return response.json() # Find by manufacturer part number result = search_by_mfn('IMXRT1060IEC') if result['response']['products']: product = result['response']['products'][0] print(f"Found: {product['description']}") print(f"Element14 Part: {product['partNumber']}") print(f"Images: {[img['url'] for img in product.get('images', [])]}") ``` ### Search by Element14 Product ID ```python def get_product_by_id(product_id, store_id=43): """Get product details by Element14 product ID""" params = { 'term': f'id:{product_id}', 'storeInfo.id': store_id, 'callInfo.apiKey': API_KEY, 'callInfo.responseDataFormat': 'json', 'resultsSettings.responseGroup': 'large' } response = requests.get(BASE_URL, params=params) return response.json() result = get_product_by_id('8947381') product = result['response']['products'][0] print(f"{product['description']}") print(f"Manufacturer: {product['manufacturer']}") print(f"Category: {product['category']}") ``` ### Get Pricing Tiers ```python def get_pricing_tiers(search_term, store_id=43): """Get tiered pricing information""" params = { 'term': f'any:{search_term}', 'storeInfo.id': store_id, 'callInfo.apiKey': API_KEY, 'callInfo.responseDataFormat': 'json', 'resultsSettings.responseGroup': 'prices' } response = requests.get(BASE_URL, params=params) return response.json() result = get_pricing_tiers('capacitor 10uF') for product in result['response']['products'][:1]: print(f"{product['partNumber']}:") for tier in product.get('pricingTiers', []): print(f" {tier['minQty']:>6} units: ${tier['price']}") ``` ### Contract Pricing with Signature ```python import hmac import hashlib from datetime import datetime from urllib.parse import quote def search_with_contract_pricing(search_term, contract_id, store_id=43): """Search with contract pricing authentication""" # Generate timestamp and signature timestamp = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ') operation = 'searchAPI' message = f'{operation}{timestamp}' signature = hmac.new( API_KEY.encode(), message.encode(), hashlib.sha1 ).hexdigest() signature_encoded = quote(signature, safe='') params = { 'term': f'any:{search_term}', 'storeInfo.id': store_id, 'callInfo.apiKey': API_KEY, 'userInfo.signature': signature_encoded, 'userInfo.timestamp': timestamp, 'userInfo.customerId': contract_id, 'callInfo.responseDataFormat': 'json', 'resultsSettings.responseGroup': 'medium' } response = requests.get(BASE_URL, params=params) return response.json() # Use contract pricing result = search_with_contract_pricing('resistor', contract_id='CUST12345') print(result) ``` ### Paginate Through All Results ```python def search_all_pages(search_term, store_id=43): """Retrieve all results with pagination""" page = 1 all_products = [] while True: params = { 'term': f'any:{search_term}', 'storeInfo.id': store_id, 'callInfo.apiKey': API_KEY, 'callInfo.responseDataFormat': 'json', 'resultsSettings.responseGroup': 'medium', 'resultsSettings.pageNumber': page, 'resultsSettings.pageSize': 50 } response = requests.get(BASE_URL, params=params) data = response.json() all_products.extend(data['response']['products']) if page >= data['response']['totalPages']: break page += 1 return all_products products = search_all_pages('microcontroller STM32') print(f"Retrieved {len(products)} total products") ``` ## JavaScript/Node.js Examples ### Basic Fetch Request ```javascript const API_KEY = "YOUR_24_CHAR_KEY"; const BASE_URL = "https://api.element14.com/catalog/products"; async function searchProducts(searchTerm, storeId = 43) { const params = new URLSearchParams({ 'term': `any:${searchTerm}`, 'storeInfo.id': storeId, 'callInfo.apiKey': API_KEY, 'callInfo.responseDataFormat': 'json', 'resultsSettings.responseGroup': 'medium', 'resultsSettings.pageSize': 20 }); const response = await fetch(`${BASE_URL}?${params}`); const data = await response.json(); return data; } // Usage searchProducts('capacitor 10uF').then(result => { console.log(`Found ${result.response.numFound} products`); result.response.products.forEach(product => { console.log(`${product.partNumber}: ${product.description}`); console.log(` $${product.unitPrice} (Stock: ${product.stockLevel})`); }); }); ``` ### Get Specific Product ```javascript async function getProductById(productId, storeId = 43) { const params = new URLSearchParams({ 'term': `id:${productId}`, 'storeInfo.id': storeId, 'callInfo.apiKey': API_KEY, 'callInfo.responseDataFormat': 'json', 'resultsSettings.responseGroup': 'large' }); const response = await fetch(`${BASE_URL}?${params}`); const data = await response.json(); return data.response.products[0] || null; } // Get product 8947381 const product = await getProductById('8947381'); console.log(product.description); console.log(product.manufacturer); ``` ### With Error Handling ```javascript async function searchWithErrorHandling(searchTerm) { try { const params = new URLSearchParams({ 'term': `any:${searchTerm}`, 'storeInfo.id': 43, 'callInfo.apiKey': API_KEY, 'callInfo.responseDataFormat': 'json' }); const response = await fetch(`${BASE_URL}?${params}`); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); if (data.response.statusCode !== 200) { throw new Error(data.response.statusMessage); } return data.response.products; } catch (error) { console.error('Search failed:', error.message); return []; } } ``` ## cURL Examples ### Simple Keyword Search ```bash curl "https://api.element14.com/catalog/products?term=any:resistor&storeInfo.id=43&callInfo.apiKey=YOUR_24_CHAR_KEY&callInfo.responseDataFormat=json" | jq ``` ### Search by Manufacturer Part Number ```bash curl -G "https://api.element14.com/catalog/products" \ --data-urlencode "term=manuPartNum:LM7805CT" \ --data-urlencode "storeInfo.id=41" \ --data-urlencode "callInfo.apiKey=YOUR_24_CHAR_KEY" \ --data-urlencode "callInfo.responseDataFormat=json" | jq ``` ### Get Product by ID with Large Response Group ```bash curl -G "https://api.element14.com/catalog/products" \ --data-urlencode "term=id:4298467" \ --data-urlencode "storeInfo.id=45" \ --data-urlencode "callInfo.apiKey=YOUR_24_CHAR_KEY" \ --data-urlencode "callInfo.responseDataFormat=json" \ --data-urlencode "resultsSettings.responseGroup=large" | jq '.response.products[0]' ``` ### Paginated Search ```bash for page in {1..5}; do echo "=== Page $page ===" curl -G "https://api.element14.com/catalog/products" \ --data-urlencode "term=any:capacitor" \ --data-urlencode "storeInfo.id=43" \ --data-urlencode "callInfo.apiKey=YOUR_24_CHAR_KEY" \ --data-urlencode "callInfo.responseDataFormat=json" \ --data-urlencode "resultsSettings.pageNumber=$page" \ --data-urlencode "resultsSettings.pageSize=10" | jq '.response.products[] | {partNumber, description, unitPrice}' done ``` ## PyFarnell Library (Unofficial) An unofficial Python wrapper simplifies access to the Farnell variant: ```python from pyfarnell import FarnellAPI # Initialize with your API key api = FarnellAPI(api_key='YOUR_24_CHAR_KEY', region='uk') # Get part by Farnell part number part = api.get_part_by_number('9876543') print(f"Part: {part['partNumber']}") print(f"Description: {part['description']}") print(f"Price: {part['unitPrice']}") print(f"Stock: {part['stockLevel']}") ``` Note: PyFarnell is unofficial and not maintained by Farnell/Element14. Check the GitHub repository for current status and regional support. ## Best Practices ### Rate Limiting - Implement exponential backoff for retries - Space requests to avoid hitting rate limits - Cache results when possible - Batch multiple searches efficiently ### Error Handling - Check HTTP status codes - Validate `statusCode` in response body - Handle rate limit (429) responses gracefully - Log failed requests for debugging ### Performance - Use appropriate `responseGroup` to minimize payload - Implement pagination for large result sets - Filter by store ID before making requests - Consider caching frequently searched terms ### Security - Never hardcode API keys in source code - Use environment variables for credentials - Implement API key rotation policies - Monitor for unusual API usage patterns --- # Regional Store Configuration The Element14 Product Search API supports product searches across 40+ regional stores and pricing configurations. Each region uses a unique store ID and may have different product availability, pricing, and currency. ## Store IDs Reference ### Asia-Pacific Region | Region | Store ID | Platform | Currency | |--------|----------|----------|----------| | Japan | 40 | Element14 | JPY | | Australia | 45 | Element14 | AUD | | Singapore | 46 | Element14 | SGD | | Malaysia | 47 | Element14 | MYR | | China | 53 | Element14 | CNY | | Hong Kong | 54 | Element14 | HKD | | Taiwan | 55 | Element14 | TWD | | Korea | 56 | Element14 | KRW | | India | 57 | Element14 | INR | | New Zealand | 59 | Element14 | NZD | ### Europe Region | Region | Store ID | Platform | Currency | |--------|----------|----------|----------| | UK/Europe | 44 | Farnell | GBP/EUR | | Germany | 48 | Farnell | EUR | | Netherlands | 49 | Farnell | EUR | | France | 50 | Farnell | EUR | | Spain | 51 | Farnell | EUR | | Italy | 52 | Farnell | EUR | | Poland | 70 | Farnell | PLN | | Austria | 75 | Farnell | EUR | | Belgium | 76 | Farnell | EUR | | Czech Republic | 77 | Farnell | CZK | | Hungary | 78 | Element14 | HUF | | Portugal | 79 | Farnell | EUR | | Romania | 81 | Farnell | RON | | Ireland | 84 | Farnell | EUR | | Greece | 85 | Farnell | EUR | | Bulgaria | 92 | Element14 | BGN | | Denmark | 89 | Farnell | DKK | | Sweden | 91 | Farnell | SEK | | Finland | 94 | Farnell | EUR | ### Americas Region | Region | Store ID | Platform | Currency | |--------|----------|----------|----------| | USA | 43 | Newark | USD | | Mexico | 74 | Element14 | MXN | | Brazil | 72 | Element14 | BRL | ### Middle East & Africa | Region | Store ID | Platform | Currency | |--------|----------|----------|----------| | Israel | 80 | Element14 | ILS | | Saudi Arabia | 82 | Element14 | SAR | | Pakistan | 83 | Element14 | PKR | | Turkey | 97 | Element14 | TRY | | Russia/CIS | 88 | Element14 | RUB | | UK (alternate) | 41 | Farnell | GBP | ## Regional Differences ### Product Availability - Product catalogs vary by region - Some items may be region-restricted due to export controls - Availability subject to local supply chains - Check local regulations for sensitive components ### Pricing and Currencies - Pricing is region-specific - Currency automatically returned in response - Exchange rates are not fixed - prices update regularly - Contract pricing may have regional variations ### Inventory - Stock levels are region-specific - Warehouses are distributed by region - Lead times and shipping may vary - Availability can differ significantly between regions ### Language Support - Element14 sites typically support English - Farnell sites may support regional languages - Documentation mostly in English - Customer support available in regional languages ## Selecting Regional Stores ### For Global Applications ```python # Map end-user location to store ID STORE_MAPPING = { 'US': 43, 'UK': 41, 'DE': 48, 'FR': 50, 'JP': 40, 'CN': 53, 'AU': 45, 'CA': 43, # Use US store } def search_by_location(search_term, location_code): store_id = STORE_MAPPING.get(location_code, 43) # Default to US return search_products(search_term, store_id) ``` ### For Multi-Region Searches ```python def search_all_regions(search_term, target_regions=['US', 'UK', 'DE', 'JP']): """Search across multiple regions""" results_by_region = {} for region in target_regions: store_id = STORE_MAPPING[region] try: result = search_products(search_term, store_id) results_by_region[region] = result['response']['products'] except Exception as e: print(f"Error searching {region}: {e}") results_by_region[region] = [] return results_by_region # Find best pricing across regions all_results = search_all_regions('resistor 10k', ['US', 'UK', 'JP']) for region, products in all_results.items(): if products: best_price = min(p['unitPrice'] for p in products) print(f"{region}: ${best_price:.4f}") ``` ## Platform-Specific Considerations ### Newark (USA) - Store ID: 43 - Primary US distributor - Strong inventory of common components - Fast shipping within USA - Best for North American projects ### Farnell (Europe & UK) - Store IDs: 41, 44, 48-52, 70, 75-77, 79, 81, 84-85, 89, 91, 94 - Multiple European warehouses - Regional pricing in local currencies - Excellent for European supply chains - Wide product range ### Element14 (Asia-Pacific & Global) - Store IDs: 40, 45-47, 53-57, 59, 72, 74, 78, 80, 82-83, 88, 92, 97 - Global distribution network - Growing inventory in emerging markets - Regional expertise and support - Bridge between East and West ## Cross-Regional Best Practices ### Finding Part Number Equivalents The same part may have different part numbers across regions: ```python def find_equivalent_parts(mfn, store_ids=[43, 41, 40]): """Find equivalent part numbers across regions""" equivalents = {} for store_id in store_ids: result = search_by_mfn(mfn, store_id) if result['response']['products']: product = result['response']['products'][0] equivalents[store_id] = product['partNumber'] return equivalents # Find equivalent part numbers equivalents = find_equivalent_parts('IMXRT1060IEC') # Result: {43: 'CF14JT10K0', 41: 'CF14JT10K0', 40: 'CF14JT10K0'} ``` ### Comparing Pricing Across Regions ```python def compare_regional_pricing(search_term, store_ids): """Compare pricing across multiple regions""" pricing = {} for store_id in store_ids: result = search_products(search_term, store_id=store_id) if result['response']['products']: product = result['response']['products'][0] pricing[store_id] = { 'price': product['unitPrice'], 'currency': product['currencyCode'], 'stock': product['stockLevel'] } return pricing # Compare across major regions regions = [43, 41, 40] # US, UK, Japan pricing = compare_regional_pricing('capacitor 10uF', regions) for store_id, info in pricing.items(): print(f"Store {store_id}: {info['price']} {info['currency']} (Stock: {info['stock']})") ``` ### Inventory Tracking by Region ```python def track_inventory_all_regions(mfn): """Track part inventory across all accessible regions""" inventory = {} major_stores = [43, 41, 40, 44, 48, 50, 53] for store_id in major_stores: result = search_by_mfn(mfn, store_id) if result['response']['products']: product = result['response']['products'][0] inventory[store_id] = product['stockLevel'] return inventory stock = track_inventory_all_regions('LM7805CT') for store_id, qty in stock.items(): print(f"Store {store_id}: {qty} units") ``` ## Regional API Endpoint All regions use the same API endpoint: ``` https://api.element14.com/catalog/products ``` The region is controlled by the `storeInfo.id` parameter, not by different endpoints. ## Rate Limiting by Region Rate limits may vary by region and customer tier. Contact your regional distributor for: - Regional rate limit policies - Burst capacity specifications - Dedicated endpoint availability - Support for high-volume integrations --- # Best Practices & Advanced Usage ## Performance Optimization ### Minimize Response Payload Use the smallest appropriate `responseGroup` for your use case: ```python # Bad: Always fetch everything result = search_products('resistor', responseGroup='large') # Good: Fetch only what you need if just_checking_availability: responseGroup = 'small' # Part number + description only elif need_pricing: responseGroup = 'prices' # Pricing tiers only elif need_images: responseGroup = 'large' # Full details with images else: responseGroup = 'medium' # Balanced (default) ``` ### Use Pagination Efficiently ```python def fetch_first_n_results(search_term, n=100): """Efficiently fetch exactly N results without fetching extra pages""" page_size = 50 total_pages = (n + page_size - 1) // page_size all_products = [] for page in range(1, total_pages + 1): result = search_products( search_term, pageSize=page_size, pageNumber=page ) all_products.extend(result['response']['products']) if len(all_products) >= n: return all_products[:n] return all_products ``` ### Cache Results ```python import time from functools import wraps def cache_with_ttl(ttl_seconds=3600): """Cache API results for specified TTL""" cache = {} def decorator(func): def wrapper(*args, **kwargs): cache_key = (func.__name__, str(args), str(sorted(kwargs.items()))) now = time.time() if cache_key in cache: result, timestamp = cache[cache_key] if now - timestamp < ttl_seconds: return result result = func(*args, **kwargs) cache[cache_key] = (result, now) return result return wrapper return decorator @cache_with_ttl(ttl_seconds=3600) # Cache for 1 hour def search_products_cached(search_term, store_id=43): return search_products(search_term, store_id) # First call hits API result1 = search_products_cached('resistor') # Subsequent calls within 1 hour use cache result2 = search_products_cached('resistor') # Fast! ``` ## Error Handling & Resilience ### Exponential Backoff Retry ```python import time import requests from requests.exceptions import RequestException def search_with_retry(search_term, max_retries=3): """Search with exponential backoff retry""" for attempt in range(max_retries): try: params = { 'term': f'any:{search_term}', 'storeInfo.id': 43, 'callInfo.apiKey': API_KEY, 'callInfo.responseDataFormat': 'json' } response = requests.get(BASE_URL, params=params, timeout=10) # Check HTTP status if response.status_code == 429: # Rate limited wait_time = 2 ** attempt print(f"Rate limited. Waiting {wait_time}s...") time.sleep(wait_time) continue response.raise_for_status() # Check API status code data = response.json() if data['response']['statusCode'] != 200: if data['response']['statusCode'] == 500 and attempt < max_retries - 1: wait_time = 2 ** attempt print(f"Server error. Retrying in {wait_time}s...") time.sleep(wait_time) continue else: raise Exception(data['response']['statusMessage']) return data except RequestException as e: if attempt < max_retries - 1: wait_time = 2 ** attempt print(f"Request failed: {e}. Retrying in {wait_time}s...") time.sleep(wait_time) else: raise raise Exception("Max retries exceeded") ``` ### Graceful Degradation ```python def search_with_fallback(search_term, primary_store=43, fallback_store=41): """Try primary store, fall back to secondary if unavailable""" try: return search_products(search_term, store_id=primary_store) except Exception as e: print(f"Primary store failed: {e}") print(f"Falling back to store {fallback_store}") try: return search_products(search_term, store_id=fallback_store) except Exception as e: print(f"Both stores failed: {e}") return None ``` ## Security Best Practices ### API Key Management ```python import os from dotenv import load_dotenv # Load from environment variables load_dotenv() API_KEY = os.getenv('ELEMENT14_API_KEY') if not API_KEY: raise ValueError("ELEMENT14_API_KEY environment variable not set") # For contract pricing CONTRACT_CUSTOMER_ID = os.getenv('ELEMENT14_CONTRACT_ID') ``` ### Secure Signature Generation ```python import hmac import hashlib from datetime import datetime from urllib.parse import quote def generate_contract_signature(api_key, operation='searchAPI'): """Generate HMAC-SHA1 signature for contract pricing""" # Use UTC timestamp timestamp = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ') # Create message message = f'{operation}{timestamp}'.encode() secret = api_key.encode() # Generate signature signature = hmac.new(secret, message, hashlib.sha1).hexdigest() return { 'timestamp': timestamp, 'signature': quote(signature, safe=''), 'message': f'{operation}{timestamp}' # For verification } # Use it sig_data = generate_contract_signature(API_KEY) print(f"Signature: {sig_data['signature']}") print(f"Timestamp: {sig_data['timestamp']}") ``` ### API Usage Monitoring ```python import logging from datetime import datetime # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) def log_api_usage(search_term, store_id, result): """Log API usage for monitoring and auditing""" num_results = result['response']['numFound'] num_returned = len(result['response']['products']) logger.info( f"Search: term={search_term}, store={store_id}, " f"found={num_results}, returned={num_returned}, " f"timestamp={datetime.utcnow().isoformat()}" ) # Use in search function result = search_products('resistor', 43) log_api_usage('resistor', 43, result) ``` ## Bulk Operations ### Batch Search Multiple Terms ```python from concurrent.futures import ThreadPoolExecutor import requests def batch_search(search_terms, max_workers=5): """Search multiple terms concurrently""" results = {} def search_term(term): try: result = search_products(term) return term, result except Exception as e: return term, {'error': str(e)} with ThreadPoolExecutor(max_workers=max_workers) as executor: futures = [executor.submit(search_term, term) for term in search_terms] for future in futures: term, result = future.result() results[term] = result return results # Search multiple terms concurrently terms = ['resistor', 'capacitor', 'microcontroller'] results = batch_search(terms) for term, result in results.items(): print(f"{term}: {result['response'].get('numFound', 'N/A')}") ``` ### Build Component Library ```python import json from pathlib import Path class ComponentLibrary: def __init__(self, storage_path='components.json'): self.storage_path = Path(storage_path) self.components = self._load() def _load(self): if self.storage_path.exists(): with open(self.storage_path) as f: return json.load(f) return {} def add_component(self, search_term, store_id=43): """Search and add component to library""" result = search_products(search_term, store_id) if result['response']['products']: product = result['response']['products'][0] self.components[product['partNumber']] = { 'description': product['description'], 'manufacturer': product['manufacturer'], 'price': product['unitPrice'], 'currency': product['currencyCode'], 'store': store_id } self._save() return product return None def _save(self): with open(self.storage_path, 'w') as f: json.dump(self.components, f, indent=2) def get_component(self, part_number): return self.components.get(part_number) def list_components(self): return list(self.components.keys()) # Usage library = ComponentLibrary('my_components.json') library.add_component('resistor 10k') library.add_component('capacitor 10uF') print(f"Library has {len(library.list_components())} components") ``` ## Data Analysis ### Find Cheapest Components ```python def find_cheapest(search_term, store_id=43, limit=5): """Find cheapest options for a search term""" result = search_products(search_term, store_id=store_id) products = result['response']['products'] sorted_products = sorted(products, key=lambda p: p['unitPrice']) return sorted_products[:limit] cheapest = find_cheapest('resistor 10k') for product in cheapest: print(f"{product['partNumber']}: ${product['unitPrice']} ({product['manufacturer']})") ``` ### Find High-Stock Items ```python def find_high_stock(search_term, min_stock=1000): """Find items with sufficient stock""" result = search_products(search_term) high_stock = [ p for p in result['response']['products'] if p['stockLevel'] >= min_stock ] return sorted(high_stock, key=lambda p: p['stockLevel'], reverse=True) items = find_high_stock('capacitor', min_stock=5000) for product in items: print(f"{product['partNumber']}: {product['stockLevel']} units") ``` ### Compare Manufacturers ```python def analyze_manufacturers(search_term): """Analyze available manufacturers for a component type""" result = search_products(search_term) manufacturers = {} for product in result['response']['products']: mfg = product['manufacturer'] if mfg not in manufacturers: manufacturers[mfg] = { 'count': 0, 'avg_price': 0, 'products': [] } manufacturers[mfg]['count'] += 1 manufacturers[mfg]['avg_price'] += product['unitPrice'] manufacturers[mfg]['products'].append(product['partNumber']) # Calculate averages for mfg in manufacturers: manufacturers[mfg]['avg_price'] /= manufacturers[mfg]['count'] return manufacturers analysis = analyze_manufacturers('resistor') for mfg, stats in analysis.items(): print(f"{mfg}: {stats['count']} products, avg ${stats['avg_price']:.4f}") ``` ## Testing ### Unit Tests for API Integration ```python import unittest from unittest.mock import patch, MagicMock class TestElement14API(unittest.TestCase): @patch('requests.get') def test_search_products_success(self, mock_get): mock_response = MagicMock() mock_response.json.return_value = { 'response': { 'statusCode': 200, 'numFound': 100, 'products': [ { 'partNumber': 'TEST123', 'description': 'Test Product', 'unitPrice': 10.00 } ] } } mock_get.return_value = mock_response result = search_products('test') self.assertEqual(result['response']['statusCode'], 200) self.assertEqual(len(result['response']['products']), 1) @patch('requests.get') def test_api_error_handling(self, mock_get): mock_response = MagicMock() mock_response.json.return_value = { 'response': { 'statusCode': 401, 'statusMessage': 'Unauthorized' } } mock_get.return_value = mock_response result = search_products('test') self.assertEqual(result['response']['statusCode'], 401) if __name__ == '__main__': unittest.main() ```