Skip to main content
PUT
/
v2
/
products
/
{id}

Update Product

Update product details including price, description, images, and metadata. Changes to UPC code will trigger a new eligibility check.

Authentication

Authorization: Bearer glm_test_YOUR_API_KEY

Path Parameters

ParameterTypeRequiredDescription
idintegerYesProduct ID

Request Body

{
  "name": "Premium Blood Pressure Monitor",
  "tagline": "Professional-grade automatic BP monitoring",
  "description": "Updated description with new features",
  "price_cents": 5495,
  "images": [
    "https://cdn.example.com/bp-monitor-updated.jpg"
  ],
  "metadata": {
    "category": "medical_devices",
    "brand": "HealthTech Pro",
    "version": "2.0"
  }
}

Parameters

All parameters are optional. Only include fields you want to update.
ParameterTypeDescription
namestringProduct name (max 255 chars)
taglinestringShort description (max 255 chars)
descriptionstringFull product description
price_centsintegerPrice in cents
currencystringISO 4217 currency code
merchant_product_idstringYour reference ID
upc_code_or_gtinstringUPC or GTIN (triggers eligibility re-check)
statusenumactive, inactive, or archived
imagesarrayArray of image URLs (replaces all existing images)
metadataobjectCustom key-value pairs (merged with existing)

Request

PUT /v2/products/{id}

Response

Returns the updated product object:
{
  "id": 12345,
  "name": "Premium Blood Pressure Monitor",
  "tagline": "Professional-grade automatic BP monitoring",
  "description": "Updated description with new features",
  "price": {
    "cents": 5495,
    "dollars": 54.95,
    "currency": "USD",
    "formatted": "$54.95"
  },
  "merchant_product_id": "BP-MONITOR-001",
  "upc_code_or_gtin": "14567890123456",
  "status": "active",
  "eligibility": {
    "hsa_fsa_eligible": true,
    "eligibility_type": "auto_substantiation",
    "reason": "SIGIS verified - Medical device",
    "checked_at": "2025-10-18T14:30:00Z"
  },
  "images": [
    {
      "id": 569,
      "url": "https://cdn.example.com/bp-monitor-updated.jpg",
      "is_primary": true
    }
  ],
  "metadata": {
    "category": "medical_devices",
    "brand": "HealthTech Pro",
    "version": "2.0"
  },
  "created_at": "2025-10-18T14:30:00Z",
  "updated_at": "2025-10-18T16:00:00Z"
}

Examples

Update Price

curl -X PUT https://api.withgale.com/v2/products/12345 \
  -H "Authorization: Bearer glm_test_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "price_cents": 5495
  }'

Update Description

curl -X PUT https://api.withgale.com/v2/products/12345 \
  -H "Authorization: Bearer glm_test_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Enhanced model with improved accuracy and larger display",
    "tagline": "Professional-grade BP monitor"
  }'

Mark as Inactive

curl -X PUT https://api.withgale.com/v2/products/12345 \
  -H "Authorization: Bearer glm_test_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "inactive"
  }'

With JavaScript

const updateProduct = async (productId, updates) => {
  const response = await fetch(
    `https://api.withgale.com/v2/products/${productId}`,
    {
      method: 'PUT',
      headers: {
        'Authorization': `Bearer ${process.env.GALE_API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(updates)
    }
  );

  if (!response.ok) {
    throw new Error('Failed to update product');
  }

  return await response.json();
};

// Usage examples

// Update price
await updateProduct(12345, {
  price_cents: 5495
});

// Update images
await updateProduct(12345, {
  images: [
    'https://cdn.example.com/product-1.jpg',
    'https://cdn.example.com/product-2.jpg'
  ]
});

// Update metadata
await updateProduct(12345, {
  metadata: {
    inventory: 100,
    warehouse: 'WEST-01'
  }
});

Use Cases

Price Updates

// Apply sale pricing
const applyDiscount = async (productId, discountPercent) => {
  const product = await getProduct(productId);
  const discountedPrice = Math.round(
    product.price.cents * (1 - discountPercent / 100)
  );

  return await updateProduct(productId, {
    price_cents: discountedPrice,
    metadata: {
      ...product.metadata,
      original_price: product.price.cents,
      discount_percent: discountPercent,
      sale_ends: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString()
    }
  });
};

// Revert to original price
const endSale = async (productId) => {
  const product = await getProduct(productId);
  const originalPrice = product.metadata?.original_price;

  if (originalPrice) {
    return await updateProduct(productId, {
      price_cents: originalPrice,
      metadata: {
        ...product.metadata,
        original_price: undefined,
        discount_percent: undefined,
        sale_ends: undefined
      }
    });
  }
};

Inventory Management

// Update stock quantity
const updateInventory = async (productId, quantity) => {
  const product = await getProduct(productId);

  // Mark as inactive if out of stock
  const newStatus = quantity > 0 ? 'active' : 'inactive';

  return await updateProduct(productId, {
    status: newStatus,
    metadata: {
      ...product.metadata,
      inventory: quantity,
      last_restocked: new Date().toISOString()
    }
  });
};

Sync from E-commerce Platform

// Sync product updates from Shopify
const syncProductFromShopify = async (galeProductId, shopifyProduct) => {
  return await updateProduct(galeProductId, {
    name: shopifyProduct.title,
    description: shopifyProduct.body_html,
    price_cents: Math.round(shopifyProduct.variants[0].price * 100),
    images: shopifyProduct.images.map(img => img.src),
    status: shopifyProduct.status === 'active' ? 'active' : 'inactive',
    metadata: {
      shopify_id: shopifyProduct.id,
      shopify_updated_at: shopifyProduct.updated_at,
      vendor: shopifyProduct.vendor
    }
  });
};

Bulk Price Update

// Increase all product prices by percentage
const bulkPriceIncrease = async (productIds, increasePercent) => {
  const results = [];

  for (const productId of productIds) {
    const product = await getProduct(productId);
    const newPrice = Math.round(
      product.price.cents * (1 + increasePercent / 100)
    );

    const updated = await updateProduct(productId, {
      price_cents: newPrice
    });

    results.push({
      id: productId,
      oldPrice: product.price.cents,
      newPrice: newPrice,
      success: true
    });
  }

  return results;
};

Re-check Eligibility

// Update UPC to trigger eligibility re-check
const recheckEligibility = async (productId, newUPC) => {
  const updated = await updateProduct(productId, {
    upc_code_or_gtin: newUPC
  });

  console.log(`Eligibility: ${updated.eligibility.hsa_fsa_eligible}`);
  console.log(`Type: ${updated.eligibility.eligibility_type}`);
  console.log(`Reason: ${updated.eligibility.reason}`);

  return updated;
};

Metadata Merging

Metadata updates are merged with existing values, not replaced:
// Existing metadata
{
  "metadata": {
    "category": "medical",
    "brand": "HealthTech"
  }
}

// Update request
{
  "metadata": {
    "inventory": 50
  }
}

// Result (merged)
{
  "metadata": {
    "category": "medical",
    "brand": "HealthTech",
    "inventory": 50
  }
}
To remove a metadata field, set it to null:
await updateProduct(productId, {
  metadata: {
    old_field: null  // Removes this field
  }
});

Webhooks

Product updates trigger the following webhook event:
{
  "type": "product.updated",
  "data": {
    "id": 12345,
    "name": "Premium Blood Pressure Monitor",
    "price": {
      "cents": 5495
    },
    "updated_at": "2025-10-18T16:00:00Z"
  }
}
See Webhooks Reference for details.

Errors

Status CodeError CodeDescription
400invalid_requestInvalid parameters
401unauthorizedInvalid or missing API key
404not_foundProduct not found
422validation_errorField validation failed
429rate_limit_exceededToo many requests
Example error:
{
  "error": {
    "code": "validation_error",
    "message": "Invalid price",
    "details": [
      {
        "field": "price_cents",
        "message": "Price must be a positive integer"
      }
    ]
  }
}

Best Practices

Partial Updates

Only send fields that changed to minimize payload size

Validate Before Update

Fetch product first to ensure it exists

Track Changes

Use metadata to store update history

Handle Webhooks

Listen for product.updated events