Update Product

The Update Product endpoint enables you to modify existing product information including pricing, inventory, descriptions, images, and availability status. This endpoint supports partial updates, allowing you to change only specific fields while preserving others. Image uploads are supported through multipart/form-data requests.

Endpoint DetailsCopied!

  • Method: PUT

  • URL: /api/v0/products/{id}

  • Content-Type: multipart/form-data (for image uploads) or application/json

  • Authentication: Required (API Key & Secret)

  • Idempotency: Supported (recommended for update operations)

Path ParametersCopied!

Parameter

Type

Required

Description

Example

id

string (UUID)

Yes

Unique product identifier

550e8400-e29b-41d4-a716-446655440000

Request ParametersCopied!

Optional Fields (Partial Update Support)

Field

Type

Description

Example

name

string

Product name (1-200 characters)

"Updated Product Name"

description

string

Product description (max 2000 characters)

"Updated description with new features"

price

number

Product price (must be > 0.01)

349.99

currency

string

3-letter ISO currency code

"EUR"

type

string

Product classification

"DIGITAL"

productType

enum

Product category (PRODUCT, SERVICE)

"SERVICE"

status

enum

Product status (ACTIVE, INACTIVE)

"INACTIVE"

weight

number

Product weight for shipping

0.75

unit

string

Unit of measurement

"kg"

quantity

number

Available quantity

150

stockCount

number

Current stock level

75

images

array

Product image files or URLs

See examples below

Validation Rules

  • Name: 1-200 characters, must be unique within your product catalog

  • Description: Maximum 2000 characters, supports markdown formatting

  • Price: Must be greater than 0.01, supports up to 2 decimal places

  • Currency: Must be valid ISO 3-letter code (USD, EUR, USDC, EURC)

  • Images: Maximum 10 images, 10MB per image, JPEG/PNG/WebP formats

  • Stock Count: Must be >= 0 for physical products

  • Weight: Must be > 0 if specified

Request ExamplesCopied!

Basic Product Update (JSON)

curl -X PUT "https://api.devdraft.com/api/v0/products/550e8400-e29b-41d4-a716-446655440000" \
  -H "x-client-key: YOUR_CLIENT_KEY" \
  -H "x-client-secret: YOUR_CLIENT_SECRET" \
  -H "x-idempotency-key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Premium Software License Pro",
    "price": 399.99,
    "description": "Enhanced annual license with premium features, priority support, and advanced analytics dashboard."
  }'

Price and Status Update

curl -X PUT "https://api.devdraft.com/api/v0/products/550e8400-e29b-41d4-a716-446655440000" \
  -H "x-client-key: YOUR_CLIENT_KEY" \
  -H "x-client-secret: YOUR_CLIENT_SECRET" \
  -H "x-idempotency-key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "price": 249.99,
    "status": "ACTIVE"
  }'

Inventory Update

curl -X PUT "https://api.devdraft.com/api/v0/products/550e8400-e29b-41d4-a716-446655440001" \
  -H "x-client-key: YOUR_CLIENT_KEY" \
  -H "x-client-secret: YOUR_CLIENT_SECRET" \
  -H "x-idempotency-key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "stockCount": 200,
    "quantity": 200,
    "status": "ACTIVE"
  }'

Update with New Images

curl -X PUT "https://api.devdraft.com/api/v0/products/550e8400-e29b-41d4-a716-446655440000" \
  -H "x-client-key: YOUR_CLIENT_KEY" \
  -H "x-client-secret: YOUR_CLIENT_SECRET" \
  -H "x-idempotency-key: $(uuidgen)" \
  -F "name=Gaming Laptop Pro" \
  -F "price=1599.99" \
  -F "description=Updated high-performance gaming laptop with latest RTX graphics" \
  -F "images=@/path/to/new-laptop1.jpg" \
  -F "images=@/path/to/new-laptop2.jpg" \
  -F "stockCount=15"

Product Type Change

curl -X PUT "https://api.devdraft.com/api/v0/products/550e8400-e29b-41d4-a716-446655440002" \
  -H "x-client-key: YOUR_CLIENT_KEY" \
  -H "x-client-secret: YOUR_CLIENT_SECRET" \
  -H "x-idempotency-key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "productType": "SERVICE",
    "unit": "hour",
    "quantity": 50,
    "stockCount": null
  }'

JavaScript/Node.js Examples

// Basic product update
const updateProduct = async (productId, updates) => {
  try {
    const response = await fetch(`https://api.devdraft.com/api/v0/products/${productId}`, {
      method: 'PUT',
      headers: {
        'x-client-key': 'YOUR_CLIENT_KEY',
        'x-client-secret': 'YOUR_CLIENT_SECRET',
        'x-idempotency-key': generateUUID(),
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(updates)
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const updatedProduct = await response.json();
    return updatedProduct;
  } catch (error) {
    console.error('Error updating product:', error);
    throw error;
  }
};

// Update product with images
const updateProductWithImages = async (productId, updates, imageFiles = []) => {
  const formData = new FormData();
  
  // Add text fields
  Object.keys(updates).forEach(key => {
    if (key !== 'images') {
      formData.append(key, updates[key]);
    }
  });
  
  // Add image files
  imageFiles.forEach(file => {
    formData.append('images', file);
  });
  
  try {
    const response = await fetch(`https://api.devdraft.com/api/v0/products/${productId}`, {
      method: 'PUT',
      headers: {
        'x-client-key': 'YOUR_CLIENT_KEY',
        'x-client-secret': 'YOUR_CLIENT_SECRET',
        'x-idempotency-key': generateUUID()
        // Don't set Content-Type for FormData - browser will set it with boundary
      },
      body: formData
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    return await response.json();
  } catch (error) {
    console.error('Error updating product with images:', error);
    throw error;
  }
};

// Usage examples
try {
  // Simple price update
  const priceUpdate = await updateProduct('550e8400-e29b-41d4-a716-446655440000', {
    price: 299.99,
    currency: 'USD'
  });
  
  // Inventory management
  const inventoryUpdate = await updateProduct('550e8400-e29b-41d4-a716-446655440001', {
    stockCount: 150,
    status: 'ACTIVE'
  });
  
  // Product rebranding
  const rebrandUpdate = await updateProduct('550e8400-e29b-41d4-a716-446655440002', {
    name: 'New Product Name',
    description: 'Updated product description with new branding',
    price: 199.99
  });
  
  console.log('Products updated successfully');
} catch (error) {
  console.error('Update failed:', error);
}

Python Example

import requests
import json

def update_product(product_id, updates, client_key, client_secret, images=None):
    url = f"https://api.devdraft.com/api/v0/products/{product_id}"
    
    headers = {
        'x-client-key': client_key,
        'x-client-secret': client_secret,
        'x-idempotency-key': str(uuid.uuid4())
    }
    
    if images:
        # Use multipart/form-data for image uploads
        files = []
        data = {}
        
        # Add text fields
        for key, value in updates.items():
            if key != 'images':
                data[key] = value
        
        # Add image files
        for image_path in images:
            files.append(('images', open(image_path, 'rb')))
        
        try:
            response = requests.put(url, headers=headers, data=data, files=files)
            response.raise_for_status()
            return response.json()
        finally:
            # Close file handles
            for _, file_handle in files:
                file_handle.close()
    else:
        # Use JSON for simple updates
        headers['Content-Type'] = 'application/json'
        response = requests.put(url, headers=headers, json=updates)
        response.raise_for_status()
        return response.json()

# Usage examples
try:
    # Price and description update
    updated_product = update_product(
        "550e8400-e29b-41d4-a716-446655440000",
        {
            "price": 349.99,
            "description": "Updated description with new features"
        },
        "YOUR_CLIENT_KEY",
        "YOUR_CLIENT_SECRET"
    )
    
    print(f"Updated product: {updated_product['name']}")
except requests.exceptions.RequestException as e:
    print(f"Error updating product: {e}")

Response FormatCopied!

Success Response (200 OK)

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Premium Software License Pro",
  "description": "Enhanced annual license with premium features, priority support, and advanced analytics dashboard.",
  "price": 399.99,
  "currency": "USD",
  "productType": "PRODUCT",
  "status": "ACTIVE",
  "stockCount": null,
  "quantity": null,
  "weight": null,
  "unit": null,
  "images": [
    "https://devdraft-images.s3.amazonaws.com/products/software-license-main.jpg",
    "https://devdraft-images.s3.amazonaws.com/products/software-license-features.jpg"
  ],
  "variations": null,
  "paymentLink": "https://pay.devdraft.com/p/premium-license-pro",
  "walletId": "abcd1234-5678-90ef-ghij-klmnopqrstuv",
  "dateAdded": "2024-01-15T10:30:00.000Z",
  "dateUpdated": "2024-01-20T14:45:00.000Z",
  "wallet": {
    "id": "abcd1234-5678-90ef-ghij-klmnopqrstuv",
    "address": "0x742d35Cc6635C0532925a3b8d",
    "blockchain": "ETHEREUM",
    "type": "APP"
  },
  "transactions": [
    {
      "id": "txn_123456789",
      "amount": 399.99,
      "currency": "USD",
      "status": "PAYMENT_PROCESSED",
      "dateCreated": "2024-01-20T15:00:00.000Z"
    }
  ]
}

Inventory Update Response

{
  "id": "550e8400-e29b-41d4-a716-446655440001",
  "name": "Wireless Bluetooth Headphones",
  "description": "Premium wireless headphones with active noise cancellation, 30-hour battery life, and superior sound quality.",
  "price": 199.99,
  "currency": "USD",
  "productType": "PRODUCT",
  "status": "ACTIVE",
  "stockCount": 200,
  "quantity": 200,
  "weight": 0.5,
  "unit": "kg",
  "images": [
    "https://devdraft-images.s3.amazonaws.com/products/headphones-main.jpg"
  ],
  "dateAdded": "2024-01-14T14:20:00.000Z",
  "dateUpdated": "2024-01-20T16:30:00.000Z",
  "walletId": "abcd1234-5678-90ef-ghij-klmnopqrstuv"
}

Error ResponsesCopied!

Validation Error (400 Bad Request)

{
  "statusCode": 400,
  "message": [
    "Price must be greater than 0",
    "Product name cannot exceed 200 characters",
    "Currency must be a valid 3-letter ISO code"
  ],
  "error": "Bad Request"
}

Product Not Found (404 Not Found)

{
  "statusCode": 404,
  "message": "Product not found",
  "error": "Not Found"
}

Invalid Product ID (400 Bad Request)

{
  "statusCode": 400,
  "message": "Invalid product ID format. Must be a valid UUID.",
  "error": "Bad Request"
}

Authentication Error (401 Unauthorized)

{
  "statusCode": 401,
  "message": "Invalid or missing API credentials",
  "error": "Unauthorized"
}

Image Upload Error (400 Bad Request)

{
  "statusCode": 400,
  "message": "Image file size exceeds 10MB limit",
  "error": "Bad Request"
}

Rate Limit Error (429 Too Many Requests)

{
  "statusCode": 429,
  "message": "Rate limit exceeded. Maximum 100 requests per minute.",
  "error": "Too Many Requests",
  "retryAfter": 60
}

Business Logic & BehaviorCopied!

Partial Updates

  • Only provided fields are updated; omitted fields remain unchanged

  • null values explicitly set fields to null

  • Empty strings are treated as valid values (will clear the field)

Image Handling

  • New images are uploaded to cloud storage and URLs are generated

  • Existing images are preserved unless explicitly replaced

  • Images are automatically optimized and resized

  • Multiple formats are generated for different use cases

Inventory Management

  • Stock count changes trigger inventory log entries

  • Automatic status changes based on stock levels (configurable)

  • Physical products require stock tracking; digital products are optional

Wallet Assignment

  • Products maintain their existing wallet assignments

  • If app's default wallet changes, products are not automatically reassigned

  • Wallet changes require explicit update requests

Price History

  • Price changes are tracked in the audit trail

  • oldPrice field can be used to show discounts and promotions

  • Currency changes preserve the numeric value but update the currency code

Advanced Use CasesCopied!

Bulk Product Updates

// Update multiple products efficiently
const bulkUpdateProducts = async (updates) => {
  const results = [];
  const batchSize = 10;
  
  for (let i = 0; i < updates.length; i += batchSize) {
    const batch = updates.slice(i, i + batchSize);
    
    const batchPromises = batch.map(({ productId, changes }) =>
      updateProduct(productId, changes)
        .then(result => ({ success: true, productId, result }))
        .catch(error => ({ success: false, productId, error: error.message }))
    );
    
    const batchResults = await Promise.all(batchPromises);
    results.push(...batchResults);
    
    // Rate limiting consideration
    if (i + batchSize < updates.length) {
      await new Promise(resolve => setTimeout(resolve, 100));
    }
  }
  
  return results;
};

// Usage
const productUpdates = [
  { productId: 'prod-1', changes: { price: 199.99, status: 'ACTIVE' } },
  { productId: 'prod-2', changes: { stockCount: 150 } },
  { productId: 'prod-3', changes: { description: 'New description' } }
];

const results = await bulkUpdateProducts(productUpdates);
console.log(`Updated ${results.filter(r => r.success).length} products`);

Dynamic Pricing Updates

// Implement dynamic pricing strategy
const applyDynamicPricing = async (productId, strategy) => {
  try {
    // Get current product data
    const product = await fetchProduct(productId);
    let newPrice = product.price;
    
    switch (strategy.type) {
      case 'DISCOUNT':
        newPrice = product.price * (1 - strategy.percentage / 100);
        break;
        
      case 'MARKUP':
        newPrice = product.price * (1 + strategy.percentage / 100);
        break;
        
      case 'FIXED_PRICE':
        newPrice = strategy.price;
        break;
        
      case 'COMPETITIVE':
        // Implement competitive pricing logic
        newPrice = calculateCompetitivePrice(product, strategy.competitors);
        break;
    }
    
    // Round to 2 decimal places
    newPrice = Math.round(newPrice * 100) / 100;
    
    // Update product with new price
    const updates = {
      price: newPrice,
      oldPrice: product.price // Store original price for reference
    };
    
    return await updateProduct(productId, updates);
  } catch (error) {
    console.error('Dynamic pricing update failed:', error);
    throw error;
  }
};

Inventory Automation

// Automatic stock management
const automateInventory = async (productId, rules) => {
  const product = await fetchProduct(productId);
  const updates = {};
  
  // Low stock alert threshold
  if (product.stockCount <= rules.lowStockThreshold) {
    console.warn(`Low stock alert for ${product.name}: ${product.stockCount} remaining`);
    
    // Auto-reorder if enabled
    if (rules.autoReorder && product.stockCount <= rules.reorderPoint) {
      updates.stockCount = product.stockCount + rules.reorderQuantity;
      console.info(`Auto-reordering ${rules.reorderQuantity} units for ${product.name}`);
    }
  }
  
  // Out of stock management
  if (product.stockCount === 0 && rules.deactivateWhenEmpty) {
    updates.status = 'INACTIVE';
    console.info(`Deactivating out-of-stock product: ${product.name}`);
  }
  
  // Back in stock activation
  if (product.stockCount > 0 && product.status === 'INACTIVE' && rules.reactivateWhenStocked) {
    updates.status = 'ACTIVE';
    console.info(`Reactivating restocked product: ${product.name}`);
  }
  
  // Apply updates if any
  if (Object.keys(updates).length > 0) {
    return await updateProduct(productId, updates);
  }
  
  return product;
};

Seasonal Pricing

// Implement seasonal pricing adjustments
const applySeasonalPricing = async (productIds, season) => {
  const seasonalRules = {
    'SUMMER': { discount: 15, categories: ['winter-clothing', 'heaters'] },
    'WINTER': { markup: 20, categories: ['winter-clothing', 'heaters'] },
    'HOLIDAY': { discount: 25, categories: ['electronics', 'toys'] },
    'BACK_TO_SCHOOL': { discount: 10, categories: ['electronics', 'books'] }
  };
  
  const rule = seasonalRules[season];
  if (!rule) return;
  
  const updates = productIds.map(async (productId) => {
    try {
      const product = await fetchProduct(productId);
      
      // Check if product category matches seasonal rule
      const categoryMatch = rule.categories.some(cat => 
        product.name.toLowerCase().includes(cat) ||
        product.description.toLowerCase().includes(cat)
      );
      
      if (!categoryMatch) return null;
      
      let newPrice;
      if (rule.discount) {
        newPrice = product.price * (1 - rule.discount / 100);
      } else if (rule.markup) {
        newPrice = product.price * (1 + rule.markup / 100);
      }
      
      return await updateProduct(productId, {
        price: Math.round(newPrice * 100) / 100,
        oldPrice: product.price
      });
    } catch (error) {
      console.error(`Failed to apply seasonal pricing to ${productId}:`, error);
      return null;
    }
  });
  
  const results = await Promise.all(updates);
  return results.filter(result => result !== null);
};

Integration PatternsCopied!

Update Validation Wrapper

// Validate updates before sending to API
const validateProductUpdate = (updates) => {
  const errors = [];
  
  if (updates.name && (updates.name.length === 0 || updates.name.length > 200)) {
    errors.push('Product name must be between 1 and 200 characters');
  }
  
  if (updates.price && updates.price <= 0) {
    errors.push('Price must be greater than 0');
  }
  
  if (updates.stockCount && updates.stockCount < 0) {
    errors.push('Stock count cannot be negative');
  }
  
  if (updates.currency && !/^[A-Z]{3}$/.test(updates.currency)) {
    errors.push('Currency must be a valid 3-letter ISO code');
  }
  
  if (errors.length > 0) {
    throw new Error(`Validation failed: ${errors.join(', ')}`);
  }
  
  return true;
};

// Safe update wrapper
const safeUpdateProduct = async (productId, updates) => {
  try {
    validateProductUpdate(updates);
    return await updateProduct(productId, updates);
  } catch (error) {
    console.error('Product update validation failed:', error);
    throw error;
  }
};

Audit Trail Integration

// Track all product changes for audit purposes
const updateProductWithAudit = async (productId, updates, userId) => {
  try {
    // Get original product for comparison
    const originalProduct = await fetchProduct(productId);
    
    // Perform update
    const updatedProduct = await updateProduct(productId, updates);
    
    // Log changes
    const changes = {};
    Object.keys(updates).forEach(key => {
      if (originalProduct[key] !== updatedProduct[key]) {
        changes[key] = {
          from: originalProduct[key],
          to: updatedProduct[key]
        };
      }
    });
    
    // Send to audit system
    await logAuditEvent({
      action: 'PRODUCT_UPDATE',
      entityId: productId,
      entityType: 'PRODUCT',
      userId: userId,
      changes: changes,
      timestamp: new Date().toISOString()
    });
    
    return updatedProduct;
  } catch (error) {
    console.error('Product update with audit failed:', error);
    throw error;
  }
};

Best PracticesCopied!

Error Handling

  • Always validate input before sending requests

  • Implement retry logic for network failures

  • Handle specific error codes appropriately

  • Log errors for monitoring and debugging

Performance

  • Use partial updates to minimize data transfer

  • Batch operations when updating multiple products

  • Implement caching for frequently updated products

  • Consider rate limiting in bulk operations

Security

  • Validate all input parameters

  • Use idempotency keys for critical updates

  • Implement proper authentication and authorization

  • Sanitize user-provided content

Data Integrity

  • Verify updates by fetching the updated product

  • Implement transaction-like behavior for related updates

  • Use optimistic locking for concurrent updates

  • Maintain backup of critical product data

Next StepsCopied!

After updating a product, you can:

  1. Verify Changes: Fetch the updated product to confirm changes

  2. Update Related Resources: Sync changes to payment links and invoices

  3. Notify Customers: Send updates about price or availability changes

  4. Monitor Performance: Track how updates affect sales and engagement

  5. Automate Workflows: Set up triggers for inventory management

For more information, see: