Skip to content

Vector Store API

API for semantic search and vector operations using Qdrant.


Base URL

https://api.vows.social/api/vector


Endpoints

Search for content using vector similarity.

Endpoint: POST /vector/search

Request:

{
  "query": "Modern garden wedding venue in Melbourne",
  "filters": {
    "region": "Melbourne",
    "vendorType": "venue",
    "minQuality": 0.8
  },
  "limit": 20,
  "offset": 0
}

Or with embedding:

{
  "embedding": [0.1, -0.2, ...],  // 384-dim vector
  "filters": {
    "region": "Melbourne"
  },
  "limit": 20
}

Response:

{
  "results": [
    {
      "id": "content-456",
      "score": 0.92,
      "payload": {
        "vendorId": "vendor-789",
        "vendorName": "Garden Weddings Melbourne",
        "vendorType": "venue",
        "region": "Melbourne",
        "qualityScore": 0.95,
        "imageUrl": "https://...",
        "description": "Beautiful botanical garden venue"
      },
      "embedding": [0.1, -0.2, ...]  // Optional
    }
  ],
  "metadata": {
    "totalResults": 1523,
    "returnedResults": 20,
    "latency_ms": 45,
    "searchMethod": "hnsw"
  }
}


Find Similar Content

Find content similar to a given content ID.

Endpoint: GET /vector/similar/:contentId

Parameters: - contentId (path) - Content ID - limit (query) - Number of results (default: 10) - minScore (query) - Minimum similarity score (0.0-1.0) - excludeSameVendor (query) - Exclude same vendor (boolean)

Request:

GET /api/vector/similar/content-456?limit=10&minScore=0.7

Response:

{
  "similar": [
    {
      "id": "content-789",
      "score": 0.89,
      "payload": {
        "vendorName": "Melbourne Botanical Venues",
        "vendorType": "venue",
        "similarity": "garden_aesthetic"
      }
    }
  ],
  "metadata": {
    "sourceContent": "content-456",
    "resultsCount": 10
  }
}


Upsert Embeddings

Upload or update vector embeddings.

Endpoint: POST /vector/upsert

Request:

{
  "collection": "content_embeddings",
  "points": [
    {
      "id": "content-456",
      "vector": [0.1, -0.2, ...],
      "payload": {
        "vendorId": "vendor-789",
        "vendorType": "venue",
        "region": "Melbourne",
        "qualityScore": 0.95,
        "timestamp": "2025-10-11T10:00:00Z"
      }
    }
  ]
}

Response:

{
  "success": true,
  "upserted": 1,
  "metadata": {
    "collection": "content_embeddings",
    "latency_ms": 25
  }
}


Delete Embeddings

Remove embeddings from vector store.

Endpoint: DELETE /vector/delete

Request:

{
  "collection": "content_embeddings",
  "ids": ["content-456", "content-789"]
}

Response:

{
  "success": true,
  "deleted": 2
}


Search multiple queries in parallel.

Endpoint: POST /vector/batch-search

Request:

{
  "queries": [
    {
      "query": "modern photographer melbourne",
      "filters": { "vendorType": "photographer" },
      "limit": 5
    },
    {
      "query": "garden venue sydney",
      "filters": { "vendorType": "venue" },
      "limit": 5
    }
  ]
}

Response:

{
  "results": [
    {
      "queryIndex": 0,
      "results": [...]
    },
    {
      "queryIndex": 1,
      "results": [...]
    }
  ],
  "metadata": {
    "totalQueries": 2,
    "totalLatency_ms": 80
  }
}


Get Collection Info

Retrieve information about a collection.

Endpoint: GET /vector/collection/:name

Response:

{
  "name": "content_embeddings",
  "vectorsCount": 15234,
  "pointsCount": 15234,
  "indexedVectorsCount": 15234,
  "config": {
    "params": {
      "vectors": {
        "size": 384,
        "distance": "Cosine"
      }
    }
  },
  "status": "green"
}


Scroll Through Collection

Paginate through vectors in a collection.

Endpoint: POST /vector/scroll

Request:

{
  "collection": "content_embeddings",
  "filter": {
    "must": [
      { "key": "region", "match": { "value": "Melbourne" } }
    ]
  },
  "limit": 100,
  "offset": 0,
  "withVectors": false
}

Response:

{
  "points": [
    {
      "id": "content-456",
      "payload": {...}
    }
  ],
  "nextOffset": 100
}


Complex filtering with multiple conditions:

{
  "embedding": [...],
  "filter": {
    "must": [
      { "key": "region", "match": { "value": "Melbourne" } },
      { "key": "qualityScore", "range": { "gte": 0.8 } }
    ],
    "should": [
      { "key": "vendorType", "match": { "value": "venue" } },
      { "key": "vendorType", "match": { "value": "photographer" } }
    ],
    "must_not": [
      { "key": "vendorId", "match": { "value": "vendor-excluded" } }
    ]
  },
  "limit": 20
}

Filter Operators: - match - Exact match - range - Numerical range (gte, gt, lte, lt) - geo_radius - Geographic search - values_count - Array length - is_empty - Null check - is_null - Null check

Combine vector similarity with BM25 text search:

{
  "query": "garden wedding venue",
  "embedding": [...],
  "hybridMode": true,
  "vectorWeight": 0.7,
  "bm25Weight": 0.3,
  "filters": {...}
}

Get aggregations along with search results:

{
  "query": "wedding photographer",
  "limit": 20,
  "facets": [
    { "field": "region", "limit": 10 },
    { "field": "priceRange", "limit": 5 }
  ]
}

Response:

{
  "results": [...],
  "facets": {
    "region": {
      "Melbourne": 234,
      "Sydney": 189,
      "Brisbane": 145
    },
    "priceRange": {
      "low": 45,
      "medium": 123,
      "high": 67
    }
  }
}


Performance Optimization

Prefiltering Strategy

For better performance, use pre-filtered collections:

# Instead of filtering at query time
POST /vector/search
{
  "query": "...",
  "filters": { "region": "Melbourne", "vendorType": "venue" }
}

# Use pre-filtered collection
POST /vector/search
{
  "collection": "melbourne_venues",  # Pre-filtered
  "query": "..."
}

Trade accuracy for speed:

{
  "query": "...",
  "limit": 20,
  "searchParams": {
    "hnsw_ef": 64,  # Lower = faster, less accurate
    "exact": false
  }
}

Quantization

Use quantized vectors for storage efficiency:

{
  "collection": "content_embeddings_quantized",
  "quantization": {
    "scalar": {
      "type": "int8",
      "quantile": 0.99
    }
  }
}

Error Handling

Collection Not Found

{
  "error": {
    "code": "COLLECTION_NOT_FOUND",
    "message": "Collection 'unknown_collection' does not exist",
    "availableCollections": [
      "content_embeddings",
      "user_embeddings",
      "vendor_embeddings"
    ]
  }
}

Invalid Vector Dimension

{
  "error": {
    "code": "INVALID_VECTOR_DIMENSION",
    "message": "Expected 384 dimensions, got 128",
    "expected": 384,
    "received": 128
  }
}

Search Timeout

{
  "error": {
    "code": "SEARCH_TIMEOUT",
    "message": "Search exceeded 5 second timeout",
    "timeout_ms": 5000,
    "suggestion": "Add more specific filters or reduce limit"
  }
}

Usage Examples

TypeScript

import { VowsClient } from '@vows/sdk';

const client = new VowsClient({ apiKey: API_KEY });

// Semantic search
const results = await client.vector.search({
  query: "modern garden wedding venue melbourne",
  filters: {
    region: "Melbourne",
    minQuality: 0.8
  },
  limit: 20
});

// Find similar
const similar = await client.vector.findSimilar('content-456', {
  limit: 10,
  minScore: 0.7
});

// Upsert embeddings
await client.vector.upsert({
  collection: 'content_embeddings',
  points: [
    {
      id: 'content-new',
      vector: embedding,
      payload: { vendorType: 'venue', region: 'Melbourne' }
    }
  ]
});

Python

from vows import VowsClient

client = VowsClient(api_key=API_KEY)

# Search
results = client.vector.search(
    query="modern photographer sydney",
    filters={"vendorType": "photographer"},
    limit=20
)

# Find similar
similar = client.vector.find_similar(
    content_id="content-456",
    limit=10
)

# Upsert
client.vector.upsert(
    collection="content_embeddings",
    points=[{
        "id": "content-new",
        "vector": embedding,
        "payload": {"vendorType": "venue"}
    }]
)

cURL

# Search
curl -X POST https://api.vows.social/api/vector/search \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "garden wedding venue",
    "filters": { "region": "Melbourne" },
    "limit": 20
  }'

# Find similar
curl https://api.vows.social/api/vector/similar/content-456?limit=10 \
  -H "Authorization: Bearer $TOKEN"

# Upsert
curl -X POST https://api.vows.social/api/vector/upsert \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "collection": "content_embeddings",
    "points": [{
      "id": "content-456",
      "vector": [0.1, -0.2, ...],
      "payload": {"vendorType": "venue"}
    }]
  }'

Best Practices

  1. Use Filters - Always filter before vector search for better performance
  2. Batch Operations - Upsert/search in batches for efficiency
  3. Cache Results - Cache common searches for 5-15 minutes
  4. Monitor Costs - Track query volume and collection size
  5. Version Embeddings - Include version in metadata for migrations


Resources