Skip to main content
The Custom Webshop integration is a channel integration that connects your custom e-commerce platform with Totebot. This allows your AI assistant to search your products, manage shopping carts, and help customers make purchases. To access this integration, navigate to IntegrationsChannelsCustom Webshop in your dashboard. Build a custom product catalog integration with ToteBot AI using your own API endpoints for product management and search.
  • Products API: paginated endpoint returning your products in a standard shape.
  • Search API: endpoint for searching products with queries and filters.
  • Get by IDs API: endpoint for fetching specific products by their IDs.

Prerequisites

  • Three publicly reachable API endpoints for products, search, and get by IDs.

Configure in Dashboard

1

Open Integrations

In your ToteBot dashboard, go to Integrations and under Custom Webshop click Connect.
2

Enter Products API URL

Paste your HTTPS endpoint that returns the first page of products. Pagination is handled with ?page and ?limit. Example: https://api.yourstore.com/products
3

Enter Search API URL

Paste your HTTPS endpoint for searching products with queries and filters. Example: https://api.yourstore.com/products/search
4

Enter Get by IDs API URL

Paste your HTTPS endpoint for fetching specific products by their IDs. Example: https://api.yourstore.com/products/by-ids
5

Enable product page knowledge (optional)

Toggle Scan product pages ON to let ToteBot crawl product pages and enrich AI responses. You can change this later.
6

Connect

Click Connect. The integration validates the URLs and saves your settings.

Products API

Your API must return products with pagination. Endpoint:
GET {productsUrl}?page=1&limit=20
Query Parameters:
  • page: 1-based page number (default: 1)
  • limit: page size (default: 20, recommended up to 250)
Response Format:
{
  "products": [
    {
      "id": "123",
      "name": "Product name",
      "description": "Optional product description",
      "url": "https://shop.example.com/products/handle",
      "productType": "Shoes",
      "tags": ["summer", "running"],
      "status": "active",
      "availability": true,
      "price": { 
        "amount": 29.99, 
        "currency": "USD" 
      },
      "images": [
        { 
          "url": "https://example.com/image.jpg", 
          "altText": "Product image" 
        }
      ],
      "created_at": "2024-01-01T00:00:00.000Z",
      "updated_at": "2024-01-02T00:00:00.000Z",
      "attributes": {
        "color": "red",
        "size": "10"
      }
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 1000,
    "hasNextPage": true
  }
}
Field Requirements:
  • Required: id, name, url, status (one of active|archived|draft), availability (boolean)
  • Recommended: description, productType, tags, price.amount, price.currency, images[], created_at, updated_at
  • Optional: attributes (key-value pairs for custom fields)

Search API

Your search API should handle product queries with optional filters. Endpoint:
GET {searchUrl}?query=running shoes&filters[availability]=true&filters[price][min]=10&filters[price][max]=100&filters[productType]=Shoes&page=1&limit=10
Query Parameters:
  • query: Search query string (required)
  • filters[availability]: Filter by availability (boolean)
  • filters[price][min]: Minimum price filter (number)
  • filters[price][max]: Maximum price filter (number)
  • filters[productType]: Filter by product type (string)
  • page: 1-based page number (default: 1)
  • limit: page size (default: 10)
Response Format:
{
  "products": [
    {
      "id": "123",
      "name": "Running Shoes",
      "description": "High-performance running shoes",
      "url": "https://shop.example.com/products/running-shoes",
      "productType": "Shoes",
      "tags": ["running", "athletic"],
      "status": "active",
      "availability": true,
      "price": { 
        "amount": 99.99, 
        "currency": "USD" 
      },
      "images": [
        { 
          "url": "https://example.com/running-shoes.jpg", 
          "altText": "Running shoes" 
        }
      ],
      "created_at": "2024-01-01T00:00:00.000Z",
      "updated_at": "2024-01-02T00:00:00.000Z",
      "attributes": {
        "color": "blue",
        "size": "10"
      }
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 10,
    "total": 25,
    "hasNextPage": true
  },
  "query": "running shoes"
}

Get by IDs API

Your get by IDs API should fetch specific products by their IDs. Endpoint:
GET {getByIdsUrl}?ids=123,456,789
Query Parameters:
  • ids: Comma-separated list of product IDs (required)
Response Format:
{
  "products": [
    {
      "id": "123",
      "name": "Product 1",
      "description": "Description for product 1",
      "url": "https://shop.example.com/products/product-1",
      "productType": "Shoes",
      "tags": ["summer"],
      "status": "active",
      "availability": true,
      "price": { 
        "amount": 49.99, 
        "currency": "USD" 
      },
      "images": [
        { 
          "url": "https://example.com/product1.jpg", 
          "altText": "Product 1" 
        }
      ],
      "created_at": "2024-01-01T00:00:00.000Z",
      "updated_at": "2024-01-02T00:00:00.000Z",
      "attributes": {
        "color": "red"
      }
    },
    {
      "id": "456",
      "name": "Product 2",
      "description": "Description for product 2",
      "url": "https://shop.example.com/products/product-2",
      "productType": "Clothing",
      "tags": ["winter"],
      "status": "active",
      "availability": false,
      "price": { 
        "amount": 79.99, 
        "currency": "USD" 
      },
      "images": [
        { 
          "url": "https://example.com/product2.jpg", 
          "altText": "Product 2" 
        }
      ],
      "created_at": "2024-01-01T00:00:00.000Z",
      "updated_at": "2024-01-02T00:00:00.000Z",
      "attributes": {
        "size": "M"
      }
    }
  ]
}
Note: If no products are found or if the ids parameter is empty, return an empty products array:
{
  "products": []
}

Reference Implementation

Here’s a complete reference implementation based on ToteBot’s own products API: Products Controller (Node.js/Express):
// GET /products?page=1&limit=20
app.get('/products', async (req, res) => {
  const { page = 1, limit = 20 } = req.query;
  
  try {
    const products = await getProductsFromDatabase(page, limit);
    const total = await getTotalProductCount();
    
    res.json({
      products: products.map(product => ({
        id: product.id,
        name: product.name,
        description: product.description,
        url: product.url,
        productType: product.productType,
        tags: product.tags,
        status: product.status,
        availability: product.availability,
        price: product.price ? {
          amount: product.price.amount,
          currency: product.price.currency
        } : undefined,
        images: product.images?.map(img => ({
          url: img.url,
          altText: img.altText
        })),
        created_at: product.created_at,
        updated_at: product.updated_at,
        attributes: product.attributes || {}
      })),
      pagination: {
        page: parseInt(page),
        limit: parseInt(limit),
        total,
        hasNextPage: (page * limit) < total
      }
    });
  } catch (error) {
    res.status(500).json({ error: 'Internal server error' });
  }
});
Search Controller:
// GET /products/search?query=shoes&filters[availability]=true&page=1&limit=10
app.get('/products/search', async (req, res) => {
  const { query, filters = {}, page = 1, limit = 10 } = req.query;
  
  if (!query) {
    return res.status(400).json({ error: 'Query parameter is required' });
  }
  
  try {
    const searchResults = await searchProducts(query, filters, page, limit);
    
    res.json({
      products: searchResults.products.map(product => ({
        // Same product mapping as above
        id: product.id,
        name: product.name,
        // ... other fields
      })),
      pagination: {
        page: parseInt(page),
        limit: parseInt(limit),
        total: searchResults.total,
        hasNextPage: (page * limit) < searchResults.total
      },
      query
    });
  } catch (error) {
    res.status(500).json({ error: 'Internal server error' });
  }
});
Get by IDs Controller:
// GET /products/ids?ids=123,456,789
app.get('/products/ids', async (req, res) => {
  const { ids } = req.query;
  
  if (!ids) {
    return res.json({ products: [] });
  }
  
  const idArray = ids.split(',').map(id => id.trim()).filter(Boolean);
  
  if (idArray.length === 0) {
    return res.json({ products: [] });
  }
  
  try {
    const products = await getProductsByIds(idArray);
    
    res.json({
      products: products.map(product => ({
        // Same product mapping as above
        id: product.id,
        name: product.name,
        // ... other fields
      }))
    });
  } catch (error) {
    res.status(500).json({ error: 'Internal server error' });
  }
});

API Validation

ToteBot will validate your API endpoints during the integration setup process:
  1. Products API: Tests connectivity and response structure
  2. Search API: Validates search functionality with a test query
  3. Get by IDs API: Ensures proper handling of product ID lookups
All endpoints must return valid JSON responses with the expected structure. If any validation fails, you’ll see specific error messages to help you fix the issues.

Error Handling

Your APIs should handle errors gracefully and return appropriate HTTP status codes: Common Error Responses:
{
  "error": "Product not found",
  "message": "The requested product ID does not exist",
  "code": "PRODUCT_NOT_FOUND"
}
HTTP Status Codes:
  • 200: Success
  • 400: Bad Request (invalid parameters)
  • 404: Not Found (product/endpoint not found)
  • 500: Internal Server Error

Security Considerations

  • HTTPS Required: All API endpoints must use HTTPS
  • Rate Limiting: Implement rate limiting to prevent abuse
  • Input Validation: Validate all query parameters and request data
  • CORS: Configure CORS headers if needed for web requests
  • Authentication: Consider adding API keys for production use

Performance Optimization

  • Caching: Implement caching for frequently accessed product data
  • Pagination: Use efficient pagination to handle large product catalogs
  • Database Indexing: Ensure proper database indexes for search queries
  • CDN: Use a CDN for product images to improve loading times

Best Practices

Data Consistency

  • Ensure product availability is real-time
  • Keep inventory updated across all channels
  • Handle price changes during checkout flow
  • Validate product data before returning responses

Testing Your Implementation

  1. API Endpoints: Test all three endpoints with various parameters
  2. Error Scenarios: Test with invalid IDs, empty responses, network errors
  3. Performance: Load test with concurrent users and large catalogs
  4. Integration: Test end-to-end with ToteBot’s conversation flow
  5. Edge Cases: Test empty product lists, malformed JSON, timeout scenarios

Validation Rules

  • Products API: Must return products array and pagination object with hasNextPage boolean
  • Search API: Must return products array, pagination object, and query string
  • Get by IDs API: Must return products array (can be empty if no products found)
  • Product Objects: Should align with the field requirements above; unknown fields go into attributes

Troubleshooting

  • Zero Products: Verify your API returns products[] and pagination.hasNextPage
  • Search Issues: Ensure your search endpoint handles queries and filters correctly
  • Connectivity: Ensure all URLs are reachable from ToteBot’s backend
  • Validation Errors: Check that your API responses match the expected JSON structure
  • Performance: Monitor response times and implement caching if needed

Common Issues

Issue: “Unable to connect to Products API”
  • Solution: Verify the URL is correct and accessible via HTTPS
Issue: “Invalid response structure from Search API”
  • Solution: Ensure your search endpoint returns the expected JSON format with products and pagination
Issue: “Get by IDs API connectivity test failed”
  • Solution: Check that your endpoint handles empty ids parameter and returns {"products": []}
Issue: Products not updating properly
  • Solution: Verify your pagination logic and ensure hasNextPage is calculated correctly
I