Level 1: SVK Primitives

Shopkeep API Reference

Core product search service providing TasteBrain-powered similarity search across millions of crawled products. Use Shopkeep for non-personalized, generic product discovery.

When to Use Shopkeep

  • • Anonymous/public product search (marketing pages, catalogs)
  • • One-off searches without user context
  • • High-performance requirements (<50ms latency)
  • • Tag generation and store creation

Note: For personalized, user-scoped search, use the Prism Service instead.

API Configuration

Base URL: https://api-shopkeep.bestomer.io/

Authentication: HTTP Bearer token

Authorization: Bearer $SHOPKEEP_TOKEN

Core Search Endpoints

1. Text Search: POST /search/text

Search products using text descriptions.

Request:

{
  "queries": ["minimalist ceramic vases with organic shapes"],
  "n_products": 30,
  "n_pool": 300,
  "noise": 0.0,
  "domains": ["cb2.com", "westelm.com"]
}

Response:

{
  "results": {
    "minimalist ceramic vases with organic shapes": [
      ["product-handle-1", 0.87],
      ["product-handle-2", 0.85],
      ["product-handle-3", 0.82]
    ]
  },
  "maxsim_time_ms": 45,
  "embed_time_ms": 12,
  "maxsim_pool_size": 300
}

Note: Response returns product handles with similarity scores. Product details must be retrieved separately.

2. Image Search: POST /search/image

Search products using image uploads (multipart/form-data).

Parameters:

  • prompt_1_image (required): Image file (JPEG, PNG, WebP)
  • prompt_1_text (optional): Text description to accompany image
  • n_products (required): Number of products to return
  • n_pool (required): Candidate pool size
  • noise (required): Ranking diversity noise
  • domains (optional): Array of domains to restrict search

TypeScript Example:

import FormData from 'form-data';
import fs from 'fs';

const formData = new FormData();
formData.append('prompt_1_image', fs.createReadStream('/path/to/image.jpg'));
formData.append('prompt_1_text', 'modern dining chairs');
formData.append('n_products', '30');
formData.append('n_pool', '300');
formData.append('noise', '0.0');

const response = await fetch('https://api-shopkeep.bestomer.io/search/image', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.SHOPKEEP_TOKEN}`,
  },
  body: formData,
});

const results = await response.json();

3. Multiple Prompts

Combine multiple images and/or text prompts:

curl -X POST https://api-shopkeep.bestomer.io/search/image \
  -H "Authorization: Bearer $SHOPKEEP_TOKEN" \
  -F "prompt_1_image=@livingroom.jpg" \
  -F "prompt_1_text=coastal grandmother aesthetic" \
  -F "prompt_2_image=@bedroom.jpg" \
  -F "prompt_2_text=neutral palette" \
  -F "n_products=50"

Search Parameters Explained

n_products

Number of final results to return:

  • Range: 1-100
  • Recommended: 20-50 for typical use cases
  • Trade-offs: Lower values = faster, more precise; Higher values = slower, more discovery

n_pool

Size of candidate pool before final ranking:

  • Default: 10 * n_products
  • Recommended: 5-15x n_products
  • Trade-offs: Smaller pool = faster, less diverse; Larger pool = slower, more diverse

noise

Standard deviation of ranking noise (adds randomness for diversity):

  • Range: 0.0 (no noise) to 1.0 (high noise)
  • Recommended: 0.05-0.2 for discovery, 0.0 for precision
  • 0.0: Deterministic ranking, always same results
  • 0.1: Slight diversity, good for "more like this"
  • 0.3+: High diversity, good for exploration

domains

Filter results to specific stores:

  • Format: Array of domain strings
  • Example: ["anthropologie.com", "cb2.com"]
  • Use cases: Brand-specific search, price range targeting, geographic availability

Performance Characteristics

Latency:

  • Text search: 30-80ms (p50), 120ms (p99)
  • Image search: 50-150ms (p50), 250ms (p99)
  • Multi-prompt search: 80-200ms (p50), 350ms (p99)

Throughput:

  • Concurrent requests: 500+ simultaneous queries
  • Queries per second: 1000+ QPS at peak load

Best Practices

1. Descriptive Text Queries

Good:

{
  "queries": ["mid-century modern oak dining chairs with tapered legs"],
  "n_products": 20,
  "n_pool": 200,
  "noise": 0.0
}

Poor:

{
  "queries": ["chairs"],
  "n_products": 20,
  "n_pool": 200,
  "noise": 0.0
}

2. Combine Text + Image

Best results come from multimodal queries:

// Upload image with text context
formData.append('prompt_1_image', imageFile);
formData.append('prompt_1_text', 'scandinavian oak furniture with clean lines');

3. Tune Pool Size for Use Case

  • Precision search (find exact match): n_pool = 3-5x n_products
  • Balanced search (typical): n_pool = 10x n_products
  • Discovery search (explore options): n_pool = 15-20x n_products

When to Use Prism Instead

Use Prism API instead of Shopkeep when:

  • You have a user context and want personalized results
  • You need to rerank based on user sentiment/captures
  • You're building user-facing discovery features
  • You want full product metadata in response (not just handles)

Related Resources