Products
Integrate Products
This guide provides practical implementation patterns for integrating CashIn's Product Management endpoints. These endpoints transform your inventory into intelligent, campaign-ready assets that drive viral growth and customer engagement through the PIIC framework.
Product Endpoints
|
Endpoint |
Method |
Purpose |
Key Parameters |
Response Data |
|---|---|---|---|---|
|
|
POST |
Create new product with images |
|
|
|
|
GET |
Retrieve all products with pagination |
|
|
|
|
PUT |
Update existing product and images |
|
Updated |
|
|
DELETE |
Remove product and category associations |
|
Success confirmation |
|
|
POST |
Assign product to category |
|
Success confirmation |
|
|
DELETE |
Remove product from category |
|
Success confirmation |
Category Endpoints
|
Endpoint |
Method |
Purpose |
Key Parameters |
Response Data |
|---|---|---|---|---|
|
|
POST |
Create product category |
|
|
|
|
GET |
Retrieve all categories |
|
|
|
|
PUT |
Update category name |
|
Updated |
|
|
DELETE |
Remove empty category |
|
Success confirmation |
|
|
GET |
Get products in specific category |
|
|
Authentication Setup
All Product Management endpoints require Bearer token authentication using your partner token.
const headers = {
'Authorization': 'Bearer <partner_token>',
'Content-Type': 'application/json'
};
// For multipart uploads (with images)
const formHeaders = {
'Authorization': 'Bearer <partner_token>'
// Content-Type is automatically set for multipart/form-data
};
Integration Patterns
Pattern 1: Complete Product Creation with Images
Handle product creation with image uploads and automatic PIIC summarization.
class ProductManager {
constructor(partnerToken) {
this.partnerToken = partnerToken;
this.baseHeaders = {
'Authorization': `Bearer ${partnerToken}`
};
}
async createProduct(productData, imageFiles = []) {
const formData = new FormData();
// Add product data
Object.keys(productData).forEach(key => {
if (productData[key] !== undefined) {
if (typeof productData[key] === 'object') {
formData.append(key, JSON.stringify(productData[key]));
} else {
formData.append(key, productData[key]);
}
}
});
// Add image files
imageFiles.forEach((file, index) => {
if (this.validateImageFile(file)) {
formData.append('images[]', file);
} else {
throw new Error(`Invalid image file at index ${index}: ${file.name}`);
}
});
try {
const response = await fetch('/partner/v1/products/new', {
method: 'POST',
headers: this.baseHeaders,
body: formData
});
const result = await response.json();
if (result.success) {
console.log('Product created with PIIC summary:', result.data.piic_summary);
return {
success: true,
product: result.data,
piicSummary: result.data.piic_summary
};
} else {
return { success: false, error: result.error, details: result.details };
}
} catch (error) {
console.error('Product creation failed:', error);
return { success: false, error: 'Network error during product creation' };
}
}
validateImageFile(file) {
const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp'];
const maxSize = 5 * 1024 * 1024; // 5MB
if (!allowedTypes.includes(file.type)) {
console.error('Invalid file type:', file.type);
return false;
}
if (file.size > maxSize) {
console.error('File too large:', file.size);
return false;
}
return true;
}
}
// Usage example
async function handleProductCreation(formData, imageFiles) {
const productManager = new ProductManager('your_partner_token');
const productData = {
name: formData.get('name'),
description: formData.get('description'),
price: parseFloat(formData.get('price')),
currency: formData.get('currency') || 'USD',
sku: formData.get('sku'),
barcode: formData.get('barcode'),
metadata: {
weight: formData.get('weight'),
dimensions: formData.get('dimensions'),
category: formData.get('category')
},
is_active: formData.get('is_active') === 'true'
};
const result = await productManager.createProduct(productData, imageFiles);
if (result.success) {
showSuccessMessage(`Product created! PIIC generated: ${result.piicSummary}`);
refreshProductList();
} else {
showErrorMessage(result.error, result.details);
}
}
Pattern 2: Intelligent Product Listing with Filtering
Implement product listing with advanced filtering and pagination for campaign integration.
class ProductListManager {
constructor(partnerToken) {
this.partnerToken = partnerToken;
this.headers = {
'Authorization': `Bearer ${partnerToken}`,
'Content-Type': 'application/json'
};
}
async getProducts(filters = {}) {
const queryParams = new URLSearchParams();
// Add pagination
queryParams.append('page', filters.page || 1);
queryParams.append('limit', filters.limit || 20);
// Add filters
if (filters.is_active !== undefined) {
queryParams.append('is_active', filters.is_active);
}
if (filters.category_id) {
queryParams.append('category_id', filters.category_id);
}
try {
const response = await fetch(`/partner/v1/products/list?${queryParams.toString()}`, {
method: 'GET',
headers: this.headers
});
const result = await response.json();
if (result.success) {
return {
success: true,
products: result.data.products,
pagination: result.data.pagination,
totalProducts: result.data.pagination.total
};
}
return { success: false, error: result.error };
} catch (error) {
console.error('Failed to fetch products:', error);
return { success: false, error: 'Network error' };
}
}
async getProductsForCampaigns() {
// Get only active products suitable for campaigns
return await this.getProducts({
is_active: true,
limit: 100 // Get more products for campaign selection
});
}
async searchProducts(searchTerm, filters = {}) {
const result = await this.getProducts(filters);
if (result.success && searchTerm) {
const filteredProducts = result.products.filter(product =>
product.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
product.description?.toLowerCase().includes(searchTerm.toLowerCase()) ||
product.sku?.toLowerCase().includes(searchTerm.toLowerCase()) ||
product.piic_summary?.toLowerCase().includes(searchTerm.toLowerCase())
);
return {
...result,
products: filteredProducts,
searchTerm
};
}
return result;
}
}
// Implementation example
async function buildProductSelector() {
const listManager = new ProductListManager('your_partner_token');
const result = await listManager.getProductsForCampaigns();
if (result.success) {
const productSelect = document.getElementById('campaign-products');
productSelect.innerHTML = '';
result.products.forEach(product => {
const option = document.createElement('option');
option.value = product.id;
option.textContent = `${product.name} - $${product.price} (${product.sku || 'No SKU'})`;
option.dataset.piicSummary = product.piic_summary;
productSelect.appendChild(option);
});
// Show PIIC summary on selection
productSelect.addEventListener('change', (e) => {
const selectedOption = e.target.selectedOptions[0];
if (selectedOption) {
document.getElementById('product-piic-summary').textContent =
selectedOption.dataset.piicSummary || 'No PIIC summary available';
}
});
}
}
Pattern 3: Dynamic Product Updates with Image Management
Handle product updates including image additions and removals.
class ProductUpdateManager {
constructor(partnerToken) {
this.partnerToken = partnerToken;
this.headers = {
'Authorization': `Bearer ${partnerToken}`
};
}
async updateProduct(productId, updates, newImages = [], removeImages = []) {
const formData = new FormData();
// Add product ID
formData.append('id', productId);
// Add update fields
Object.keys(updates).forEach(key => {
if (updates[key] !== undefined) {
if (typeof updates[key] === 'object') {
formData.append(key, JSON.stringify(updates[key]));
} else {
formData.append(key, updates[key]);
}
}
});
// Add images to remove
if (removeImages.length > 0) {
formData.append('remove_images', JSON.stringify(removeImages));
}
// Add new images
newImages.forEach(file => {
formData.append('images[]', file);
});
try {
const response = await fetch('/partner/v1/products/update', {
method: 'PUT',
headers: this.headers,
body: formData
});
const result = await response.json();
if (result.success) {
return {
success: true,
product: result.data,
updatedPiicSummary: result.data.piic_summary
};
}
return { success: false, error: result.error };
} catch (error) {
console.error('Product update failed:', error);
return { success: false, error: 'Network error during update' };
}
}
async toggleProductStatus(productId, isActive) {
return await this.updateProduct(productId, { is_active: isActive });
}
async updateProductPricing(productId, price, currency = 'USD') {
return await this.updateProduct(productId, { price, currency });
}
async bulkUpdateProducts(updates) {
const results = [];
for (const update of updates) {
const result = await this.updateProduct(
update.id,
update.data,
update.newImages,
update.removeImages
);
results.push({ id: update.id, ...result });
}
return results;
}
}
// Usage example
async function handleProductImageUpdate(productId, newFiles, imagesToRemove) {
const updateManager = new ProductUpdateManager('your_partner_token');
const result = await updateManager.updateProduct(
productId,
{}, // No other updates, just images
newFiles,
imagesToRemove
);
if (result.success) {
showSuccessMessage('Product images updated successfully!');
refreshProductDisplay(result.product);
// Show updated PIIC summary if it changed
if (result.updatedPiicSummary) {
displayPiicSummary(result.updatedPiicSummary);
}
} else {
showErrorMessage(result.error);
}
}
Pattern 4: Category Management and Product Association
Implement comprehensive category management with product relationships.
class CategoryManager {
constructor(partnerToken) {
this.partnerToken = partnerToken;
this.headers = {
'Authorization': `Bearer ${partnerToken}`,
'Content-Type': 'application/json'
};
}
async createCategory(name) {
try {
const response = await fetch('/partner/v1/category/new', {
method: 'POST',
headers: this.headers,
body: JSON.stringify({ name })
});
const result = await response.json();
if (result.success) {
return {
success: true,
category: result.data,
piicSummary: result.data.piic_summary
};
}
return { success: false, error: result.error };
} catch (error) {
console.error('Category creation failed:', error);
return { success: false, error: 'Network error' };
}
}
async getCategories(includeProducts = false) {
const queryParams = includeProducts ? '?include_products=true' : '';
try {
const response = await fetch(`/partner/v1/category/list${queryParams}`, {
method: 'GET',
headers: this.headers
});
const result = await response.json();
if (result.success) {
return {
success: true,
categories: result.data.categories
};
}
return { success: false, error: result.error };
} catch (error) {
console.error('Failed to fetch categories:', error);
return { success: false, error: 'Network error' };
}
}
async assignProductToCategory(productId, categoryId) {
try {
const response = await fetch('/partner/v1/products/assign-category', {
method: 'POST',
headers: this.headers,
body: JSON.stringify({
product_id: productId,
category_id: categoryId
})
});
const result = await response.json();
return { success: result.success, message: result.message, error: result.error };
} catch (error) {
console.error('Product assignment failed:', error);
return { success: false, error: 'Network error' };
}
}
async removeProductFromCategory(productId, categoryId) {
try {
const response = await fetch('/partner/v1/products/remove-category', {
method: 'DELETE',
headers: this.headers,
body: JSON.stringify({
product_id: productId,
category_id: categoryId
})
});
const result = await response.json();
return { success: result.success, message: result.message, error: result.error };
} catch (error) {
console.error('Product removal failed:', error);
return { success: false, error: 'Network error' };
}
}
async getCategoryProducts(categoryId) {
try {
const response = await fetch(`/partner/v1/category/${categoryId}/products`, {
method: 'GET',
headers: this.headers
});
const result = await response.json();
if (result.success) {
return {
success: true,
category: result.data.category,
products: result.data.products
};
}
return { success: false, error: result.error };
} catch (error) {
console.error('Failed to fetch category products:', error);
return { success: false, error: 'Network error' };
}
}
async deleteCategory(categoryId, reassignProducts = false) {
if (reassignProducts) {
// First check for associated products
const categoryData = await this.getCategoryProducts(categoryId);
if (categoryData.success && categoryData.products.length > 0) {
throw new Error('Category has associated products. Reassign them first.');
}
}
try {
const response = await fetch('/partner/v1/category/delete', {
method: 'DELETE',
headers: this.headers,
body: JSON.stringify({ id: categoryId })
});
const result = await response.json();
return { success: result.success, message: result.message, error: result.error };
} catch (error) {
console.error('Category deletion failed:', error);
return { success: false, error: 'Network error' };
}
}
}
// Implementation example
async function buildCategoryProductManager() {
const categoryManager = new CategoryManager('your_partner_token');
// Load categories and products
const [categoriesResult, productsResult] = await Promise.all([
categoryManager.getCategories(true),
new ProductListManager('your_partner_token').getProducts()
]);
if (categoriesResult.success && productsResult.success) {
renderCategoryProductInterface(categoriesResult.categories, productsResult.products);
}
}
async function handleProductCategoryAssignment(productId, categoryId) {
const categoryManager = new CategoryManager('your_partner_token');
const result = await categoryManager.assignProductToCategory(productId, categoryId);
if (result.success) {
showSuccessMessage('Product assigned to category successfully!');
refreshCategoryView();
} else {
showErrorMessage(result.error);
}
}
Complete Product Management Integration
Unified Product Management System
class CashInProductSystem {
constructor(partnerToken) {
this.partnerToken = partnerToken;
this.productManager = new ProductManager(partnerToken);
this.listManager = new ProductListManager(partnerToken);
this.updateManager = new ProductUpdateManager(partnerToken);
this.categoryManager = new CategoryManager(partnerToken);
}
async initializeProductSystem() {
try {
const [categories, products] = await Promise.all([
this.categoryManager.getCategories(true),
this.listManager.getProducts({ limit: 50 })
]);
return {
success: true,
categories: categories.categories || [],
products: products.products || [],
pagination: products.pagination
};
} catch (error) {
console.error('Failed to initialize product system:', error);
return { success: false, error: 'System initialization failed' };
}
}
async createProductWithCategory(productData, imageFiles, categoryName) {
// Create category if it doesn't exist
let categoryId;
const categories = await this.categoryManager.getCategories();
if (categories.success) {
const existingCategory = categories.categories.find(cat =>
cat.name.toLowerCase() === categoryName.toLowerCase()
);
if (existingCategory) {
categoryId = existingCategory.id;
} else {
const newCategory = await this.categoryManager.createCategory(categoryName);
if (newCategory.success) {
categoryId = newCategory.category.id;
}
}
}
// Create product
const productResult = await this.productManager.createProduct(productData, imageFiles);
if (productResult.success && categoryId) {
// Assign to category
await this.categoryManager.assignProductToCategory(
productResult.product.id,
categoryId
);
return {
...productResult,
categoryAssigned: true,
categoryId
};
}
return productResult;
}
async getProductsForCampaign(campaignType = 'viral') {
const products = await this.listManager.getProducts({ is_active: true });
if (!products.success) return products;
// Filter products based on viral potential (using PIIC summaries)
const campaignReadyProducts = products.products.filter(product => {
// Products with good PIIC summaries are better for campaigns
return product.piic_summary && product.piic_summary.length > 50;
});
return {
success: true,
products: campaignReadyProducts,
totalCount: campaignReadyProducts.length
};
}
async bulkUpdateProductStatus(productIds, isActive) {
const updates = productIds.map(id => ({
id,
data: { is_active: isActive }
}));
return await this.updateManager.bulkUpdateProducts(updates);
}
async deleteProductSafely(productId) {
try {
const response = await fetch('/products/delete', {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${this.partnerToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ id: productId })
});
const result = await response.json();
return { success: result.success, message: result.message, error: result.error };
} catch (error) {
console.error('Product deletion failed:', error);
return { success: false, error: 'Network error during deletion' };
}
}
async generateProductInsights() {
const products = await this.listManager.getProducts({ limit: 100 });
if (!products.success) return products;
const insights = {
totalProducts: products.products.length,
activeProducts: products.products.filter(p => p.is_active).length,
averagePrice: products.products.reduce((sum, p) => sum + (p.price || 0), 0) / products.products.length,
productsWithImages: products.products.filter(p => p.image_url && p.image_url.length > 0).length,
productsWithPiicSummaries: products.products.filter(p => p.piic_summary).length,
priceRanges: this.calculatePriceRanges(products.products),
topCategories: await this.getTopCategories()
};
return { success: true, insights };
}
calculatePriceRanges(products) {
const ranges = {
under25: 0,
range25to50: 0,
range50to100: 0,
over100: 0
};
products.forEach(product => {
const price = product.price || 0;
if (price < 25) ranges.under25++;
else if (price < 50) ranges.range25to50++;
else if (price < 100) ranges.range50to100++;
else ranges.over100++;
});
return ranges;
}
async getTopCategories() {
const categories = await this.categoryManager.getCategories(true);
if (!categories.success) return [];
return categories.categories
.map(cat => ({
name: cat.name,
productCount: cat.product_count || 0,
piicSummary: cat.piic_summary
}))
.sort((a, b) => b.productCount - a.productCount)
.slice(0, 5);
}
}
Error Handling and Best Practices
Comprehensive Error Management
class ProductErrorHandler {
static handleProductError(error, context = {}) {
console.error('Product management error:', error, context);
switch (error.type || error.error) {
case 'Validation failed':
return {
userMessage: ProductErrorHandler.formatValidationErrors(error.details),
retry: false
};
case 'File too large':
return {
userMessage: `Image file too large. Maximum size: ${error.details?.max_file_size || '5MB'}`,
retry: false
};
case 'Product with this SKU already exists':
return {
userMessage: 'A product with this SKU already exists. Please use a different SKU.',
retry: false
};
case 'Cannot delete category: has associated products':
return {
userMessage: `Cannot delete category: ${error.details?.associated_products_count || 'some'} products are still assigned. Please reassign them first.`,
retry: false,
action: 'reassign_products'
};
default:
return {
userMessage: 'An unexpected error occurred. Please try again.',
retry: true
};
}
}
static formatValidationErrors(details) {
if (!details) return 'Validation failed';
return Object.entries(details)
.map(([field, message]) => `${field}: ${message}`)
.join(', ');
}
}
Testing Your Integration
Product Management Tests
async function testProductManagement() {
const productSystem = new CashInProductSystem('sk_test_your_test_key');
console.log('Testing product system initialization...');
const initResult = await productSystem.initializeProductSystem();
console.log('Init result:', initResult);
console.log('Testing product creation...');
const createResult = await productSystem.createProductWithCategory({
name: 'Test Product',
description: 'A test product for viral campaigns',
price: 29.99,
sku: 'TEST-001'
}, [], 'Test Category');
console.log('Create result:', createResult);
console.log('Testing campaign-ready products...');
const campaignProducts = await productSystem.getProductsForCampaign();
console.log('Campaign products:', campaignProducts);
console.log('Testing product insights...');
const insights = await productSystem.generateProductInsights();
console.log('Insights:', insights);
}
// Run tests in development
if (process.env.NODE_ENV === 'development') {
window.testProducts = testProductManagement;
}
This comprehensive integration guide provides all the tools needed to implement CashIn's Product Management system, enabling you to transform your inventory into intelligent, campaign-ready assets that drive viral growth through the PIIC framework.
Product Endpoint DetailsCreate Product (
List Products (
Update Product (
Delete Product (
Assign Product to Category (
Remove Product from Category (
|
Category Endpoint DetailsCreate Category (
List Categories (
Update Category (
Delete Category (
Get Category Products (
|