DocumentationDocumentation
Talk2Sync Documentation
User Documentation
Connector APIs
  • English
  • Español
Talk2Sync Documentation
User Documentation
Connector APIs
  • English
  • Español
  • User Guide Portal & API Documentation
  • User-documentation

    • User Documentation
    • Guide

      • User Guide: Introduction
      • Core Concepts
    • Talk2sync

      • Connection Buttons
      • Color Coding System
      • Issues and Alerts
      • Command Filters
      • Deleted Information Still Appears: How to Remove It
      • Deletions
    • Conexiones

      • Connection Settings
    • Fields

      • Time Based Sync
      • Data Governance
      • Special and Extra Fields
    • Productos

      • Product Fields
      • Equivalences
      • Product Search
      • Link / Unlink Products
    • Ventas

      • Fields
      • Equivalences
      • Sales Search
      • No SKU (Missing SKU)
    • Reports

      • Product Export
      • Sales Report
    • Faq

      • Amazon

        • Amazon Barcode Requirements
        • Amazon Catalog Discrepancies and ASIN Mismatches
        • Amazon Manufacturer Requirements
        • New ASIN Creation Errors and Invalid Attribute Values
        • Talk2sync, SKUs, and Product Identifiers
        • Amazon Variation Templates
      • Mercadolibre

        • Mercado Libre Official Stores
        • Mercado Libre Locations and Geographic Attributes
        • Mercado Libre Pick-up in Store
        • Mercado Libre Extra Attributes
        • Mercado Libre Image Processing and Synchronization
        • Mercado Libre Seller Unable to List Error
      • Linio

        • Linio Brand Not Registered Error
        • Linio Physical Dimensions and Weight Requirements
  • Connector APIs

    • Connector APIs
    • Quick-start

      • Introduction & Requirements
      • Add Connection
      • Configure Connection
      • Generate Keys
      • Test Your Integration
    • Webhooks

      • Webhooks API
      • Catalog

        • Webhooks: List Products
        • Webhooks: List Product by ID
        • Webhooks: Add/Update Product
      • Sales

        • Webhooks: List Orders
        • List Order by ID
        • Add/Update Order
    • Reverse-connections

      • Reverse Connections
      • Implementation-states

        • Implementation
        • Query Implementation: Products and Orders
        • Store Implementation: Products and Orders
        • Sleep and Timeouts
      • Protocol

        • Protocol
        • Overview
        • Product Upload
        • Order Upload
        • Product Download
        • Order Download
      • Rest-calls

        • REST Calls
        • Fetching-changes

          • Fetching Changes REST Calls
          • Ask if Fetching
          • Catalog

            • Push Products Page
            • Set Finish Product Pushes
          • Sales

            • Push Orders Page
            • Set Finish Order Pushes
            • Set Finish All Pushes
        • Pulling-changes

          • Pulling Changes REST Calls
          • Ask if Pulling
          • Catalog

            • Get Next Product to Pull
            • Pull Products Page
            • Notify Product Storage Success
            • Notify Product Storage Failure
            • Set Finish Product Download
          • Sales

            • Get Next Order to Pull
            • Pull Orders Page
            • Notify Order Storage Success
            • Notify Order Storage Failure
            • Set Finish Order Download
            • Transact Finish Pull

Webhooks: Add/Update Product

Overview

The Add/Update Product webhook allows Talk2sync to create new products or update existing ones in your system. Talk2sync sends a POST request with complete product data that your application must insert or update in your database.

This endpoint implements an upsert operation (insert or update) where Talk2sync either creates a new product or updates an existing one based on the product ID.

Request Format

HTTP Request

POST https://www.example.com/your/endpoint/url?jobid=123&id=999999
T2SKey: {{API_KEY}}
Content-Type: application/json

{
  "_id": "999999",
  "sku": "999999",
  "last_updated": 1517360038797,
  "title": "EON618S JBL SUBWOOFER 18\" AMPLIFICADO",
  "url": "",
  "brand": "",
  "mpn": "",
  "model": "",
  "description": "JBL Premium Transducers",
  "variations": [
    {
      "availabilities": [
        {
          "tag": "default",
          "quantity": 50
        }
      ],
      "prices": [
        {
          "tag": "default",
          "currency": "USD",
          "number": 1060.51
        }
      ],
      "images": [
        {
          "url": "https://www.example.com/13080-thickbox_default/eon618s-jbl-subwoofer-18-amplificado-.jpg"
        }
      ],
      "videos": [
        {
          "url": ""
        }
      ],
      "barcode": "",
      "size": "",
      "color": "",
      "variationid": ""
    }
  ],
  "properties": [
    {
      "extraattributes": {
        "promociones": "",
        "status": "",
        "condicion_venta": "",
        "peso": "",
        "relacionados": "",
        "custom_01": "",
        "custom_02": "1",
        "custom_03": ""
      }
    }
  ]
}

Request Parameters

ParameterTypeDescriptionRequired
jobidintegerUnique identifier for this sync job (for tracking)✓ Yes
idstringProduct ID to insert/update✓ Yes
T2SKeyheaderYour security key✓ Yes

Request Body

The request body contains the complete product object with all details. Refer to List Products for a complete field reference.


Success Response

If the product is successfully created or updated, return a 200 OK response with the following JSON structure:

{
  "success": true,
  "code": 200,
  "warnings": [],
  "product": {
    "_id": "100004777",
    "sku": "100004777",
    "last_updated": 1517360038797,
    "title": "EON618S JBL SUBWOOFER 18\" AMPLIFICADO",
    "url": "",
    "brand": "",
    "mpn": "",
    "model": "",
    "description": "JBL Premium Transducers",
    "variations": [
      {
        "availabilities": [
          {
            "tag": "default",
            "quantity": 50
          }
        ],
        "prices": [
          {
            "tag": "default",
            "currency": "USD",
            "number": 1060.51
          }
        ],
        "images": [
          {
            "url": "https://www.example.com/13080-thickbox_default/eon618s-jbl-subwoofer-18-amplificado-.jpg"
          }
        ],
        "videos": [
          {
            "url": ""
          }
        ],
        "barcode": "",
        "size": "",
        "variationid": ""
      }
    ],
    "properties": [
      {
        "extraattributes": {
          "promociones": "",
          "status": "",
          "condicion_venta": "",
          "peso": "",
          "relacionados": "",
          "custom_01": "",
          "custom_02": "1",
          "custom_03": ""
        }
      }
    ]
  }
}

Success Response Fields

FieldTypeDescription
successbooleanAlways true for successful operations
codeintegerHTTP status code (e.g., 200)
warningsarrayArray of warning messages (if any non-critical issues)
productobjectThe successfully created/updated product object

Warnings Example

You can include non-critical warnings if certain fields were adjusted:

{
  "success": true,
  "code": 200,
  "warnings": [
    {
      "msg": "Image URL was invalid and has been skipped"
    },
    {
      "msg": "Price was adjusted to match your store's currency"
    }
  ],
  "product": { ... }
}

Error Response

If the operation fails, return an error response with detailed information about what went wrong:

{
  "success": false,
  "code": 400,
  "error": "Could not upsert product",
  "reasons": [
    {
      "msg": "Invalid price zero"
    },
    {
      "msg": "Invalid repeated title"
    },
    {
      "msg": "Invalid images"
    }
  ],
  "warnings": []
}

Error Response Fields

FieldTypeDescription
successbooleanAlways false for failed operations
codeintegerHTTP status code (e.g., 400, 500)
errorstringHigh-level error message
reasonsarrayArray of specific error reasons
warningsarrayAny warnings that occurred before the failure

Common Error Scenarios

Validation Errors (400 Bad Request)

{
  "success": false,
  "code": 400,
  "error": "Validation failed",
  "reasons": [
    {
      "msg": "Title is required"
    },
    {
      "msg": "Price must be greater than zero"
    }
  ],
  "warnings": []
}

Database Errors (500 Internal Server Error)

{
  "success": false,
  "code": 500,
  "error": "Database operation failed",
  "reasons": [
    {
      "msg": "Could not connect to database"
    }
  ],
  "warnings": []
}

Authentication Error (401 Unauthorized)

{
  "success": false,
  "code": 401,
  "error": "Unauthorized",
  "reasons": [
    {
      "msg": "Invalid or missing API key"
    }
  ],
  "warnings": []
}

Implementation Example (Node.js/Express)

app.post('/api/products', (req, res) => {
  const { jobid, id } = req.query;
  const apiKey = req.headers['t2skey'];
  const productData = req.body;

  // Validate API key
  if (apiKey !== process.env.TALK2SYNC_KEY) {
    return res.status(401).json({
      success: false,
      code: 401,
      error: 'Unauthorized',
      reasons: [{ msg: 'Invalid or missing API key' }],
      warnings: []
    });
  }

  try {
    // Validate product data
    const validationErrors = validateProduct(productData);
    if (validationErrors.length > 0) {
      return res.status(400).json({
        success: false,
        code: 400,
        error: 'Validation failed',
        reasons: validationErrors.map(msg => ({ msg })),
        warnings: []
      });
    }

    // Perform upsert operation
    const savedProduct = upsertProduct(id, productData);

    // Return success response
    res.json({
      success: true,
      code: 200,
      warnings: [],
      product: savedProduct
    });

  } catch (error) {
    console.error('Error upserting product:', error);
    res.status(500).json({
      success: false,
      code: 500,
      error: 'Database operation failed',
      reasons: [{ msg: error.message }],
      warnings: []
    });
  }
});

// Validation function
function validateProduct(product) {
  const errors = [];

  // Check required fields
  if (!product.title || product.title.trim() === '') {
    errors.push('Title is required');
  }

  // Validate variations
  if (!product.variations || product.variations.length === 0) {
    errors.push('At least one variation is required');
  }

  // Validate prices
  product.variations?.forEach((variation, idx) => {
    variation.prices?.forEach((price, priceIdx) => {
      if (price.number <= 0) {
        errors.push(`Variation ${idx}: Price ${priceIdx} must be greater than zero`);
      }
    });
  });

  // Validate images
  product.variations?.forEach((variation, idx) => {
    variation.images?.forEach((image, imgIdx) => {
      if (!isValidUrl(image.url)) {
        errors.push(`Variation ${idx}: Image ${imgIdx} has invalid URL`);
      }
    });
  });

  return errors;
}

function isValidUrl(string) {
  try {
    new URL(string);
    return true;
  } catch (_) {
    return false;
  }
}

// Upsert function
function upsertProduct(id, productData) {
  // Check if product exists
  const existingProduct = findProductById(id);

  if (existingProduct) {
    // Update existing product
    return updateProductInDatabase(id, productData);
  } else {
    // Insert new product
    return insertProductInDatabase(productData);
  }
}

Response Status Codes

StatusMeaningResponseAction
200 OKProduct created/updated successfullySuccess response with productTalk2sync records the operation
400 Bad RequestValidation error in product dataError response with reasonsCheck validation errors
401 UnauthorizedInvalid or missing API keyError responseVerify your security key
409 ConflictProduct conflicts with existing dataError response with reasonsResolve the conflict
500 Internal Server ErrorServer errorError response with error messageCheck your server logs

Best Practices

✓ Do:

  • Validate all required fields before insertion/update
  • Return specific error messages in the reasons array
  • Include warnings for non-critical issues
  • Always validate the API key
  • Use transactions for database operations (if supported)
  • Update the last_updated timestamp to current time
  • Log all operations for debugging

✗ Don't:

  • Accept partial product data (require complete objects)
  • Silently skip invalid fields
  • Return vague error messages
  • Modify data that wasn't sent by Talk2sync
  • Update products that don't belong to the current account/store
  • Ignore validation errors

Upsert Logic

The upsert operation should work as follows:

IF product with ID exists in database
  THEN update all fields with new data
ELSE
  CREATE new product with provided data
END

Create vs Update

OperationWhenAction
CREATE (INSERT)Product ID doesn't existInsert a new product record
UPDATEProduct ID already existsReplace all fields with new data

Data Consistency

  • Timestamps: Always use the last_updated timestamp from Talk2sync (don't generate a new one)
  • Product ID: The _id and id parameter should match
  • SKU: Store the SKU for reference; it should match the _id in most cases
  • Relationships: Clear any old variations/properties before updating

Idempotency

This operation is idempotent, meaning calling it multiple times with the same data should produce the same result:

  • First call: Creates/updates the product
  • Second call (same data): Returns the same success response
  • Third call (same data): Returns the same success response

This ensures that if Talk2sync retries the operation, no duplicate products are created.


Request/Response Size Limits

  • Maximum request size: 10 MB per product
  • Response should be kept under 5 MB
  • Process requests within 1 minute timeout

Related Webhooks

  • List Products
  • List Product by ID

Related Documentation

  • Quick Start: Generate Keys
  • Webhooks Overview
Last Updated: 8/28/26, 12:58 AM
Prev
Webhooks: List Product by ID