← Blog

Claude API Embeddings for Search: The Right Architecture

2026-10-13 · 5 min read · SubToAPI Team

If you're looking for a claude-embeddings endpoint, it doesn't exist. Anthropic's Claude API is a text generation API — it takes messages in and returns completions, tool calls, or streamed tokens out. It does not expose a vector embeddings endpoint the way OpenAI's text-embedding-3 or Cohere's embed models do.

That's not a dead end, though. Most "embeddings for search" use cases don't actually need Claude to produce embeddings — they need a vector search layer plus Claude as the generation/synthesis layer. This is the standard RAG (retrieval-augmented generation) pattern, and Claude is excellent at the generation half. You just pair it with a dedicated embeddings model for the retrieval half. Below is the architecture that works in production, with working code.

Why Claude doesn't do embeddings

Embedding models and generative language models are trained differently. Embedding models are optimized to map text into a fixed-length vector space where semantic similarity corresponds to vector distance (cosine similarity, dot product, etc.). Generative models like Claude are optimized to predict the next token conditioned on a long context. You could, in theory, extract hidden-state activations from a generative model and call them "embeddings," but Anthropic doesn't expose this, and even if it did, a purpose-built embedding model would outperform it for retrieval tasks.

So the practical answer to "Claude API embeddings for search" is: use a dedicated embeddings provider for the vectors, and use Claude for everything downstream of retrieval — ranking context, writing the answer, citing sources, following instructions about tone and format.

The architecture: embed, retrieve, generate

User query
   │
   ▼
Embedding model (Voyage AI, OpenAI, Cohere, open-source)
   │  → query vector
   ▼
Vector store (pgvector, Pinecone, Weaviate, Qdrant, etc.)
   │  → top-k matching chunks
   ▼
Claude (via SubToAPI or direct Anthropic API)
   │  → synthesized, grounded answer
   ▼
Response to user

Three independent pieces, each replaceable:

  1. Embedding model — turns text into vectors. Voyage AI is worth noting because Anthropic has recommended it in their own RAG documentation, but OpenAI and Cohere embeddings work fine too.
  2. Vector store — stores vectors and does similarity search. Pick based on scale and infra preference, not on which LLM you use for generation.
  3. Claude — takes the retrieved chunks, synthesizes a grounded, well-formatted answer, and can cite sources.

Step 1: Embed and index your documents

// Pseudocode — swap in your embeddings provider's SDK
async function embedAndStore(documents) {
  for (const doc of documents) {
    const vector = await embeddingClient.embed(doc.text);
    await vectorStore.upsert({
      id: doc.id,
      vector,
      metadata: { text: doc.text, source: doc.source }
    });
  }
}

Chunk size matters more than most people assume. For search-and-answer use cases, 300–800 tokens per chunk with some overlap tends to balance retrieval precision against the context Claude needs to actually answer well.

Step 2: Retrieve relevant chunks

async function retrieve(query, k = 5) {
  const queryVector = await embeddingClient.embed(query);
  const results = await vectorStore.query({ vector: queryVector, topK: k });
  return results.map(r => r.metadata.text);
}

Step 3: Hand the retrieved context to Claude

This is where Claude does the actual work the search intent behind "embeddings for search" usually cares about: turning raw matched text into a coherent, cited answer. If you're routing Claude calls through SubToAPI, this looks like a normal Messages request with your retrieved chunks injected into the prompt:

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-5",
    "max_tokens": 1024,
    "messages": [
      {
        "role": "user",
        "content": "Context:\n[CHUNK_1]\n[CHUNK_2]\n[CHUNK_3]\n\nQuestion: How do I rotate API keys?\n\nAnswer using only the context above. Cite which chunk each fact came from."
      }
    ]
  }'

Or in JavaScript, same pattern wired into the retrieval step:

async function answerWithContext(query) {
  const chunks = await retrieve(query);
  const prompt = `Context:\n${chunks.join("\n\n")}\n\nQuestion: ${query}\n\nAnswer using only the context above.`;

  const res = await fetch("https://api.subtoapi.app/v1/messages", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      model: "claude-sonnet-4-5",
      max_tokens: 1024,
      messages: [{ role: "user", content: prompt }]
    })
  });

  const data = await res.json();
  return data.content;
}

Full request/response shape is in the Messages docs. For longer answers or chat-style UIs, stream the response instead of waiting for the full completion — see streaming.

When tool use beats a static pipeline

A static "retrieve then answer" pipeline works for simple Q&A, but it breaks down when the first retrieval doesn't return good matches, or the question needs multiple searches (e.g., "compare X and Y" requires two separate lookups). In that case, give Claude a search tool and let it decide when and how many times to query your vector store:

{
  "name": "search_docs",
  "description": "Search the knowledge base and return relevant chunks",
  "input_schema": {
    "type": "object",
    "properties": {
      "query": { "type": "string" }
    },
    "required": ["query"]
  }
}

Claude calls the tool, you run the embedding + vector search behind it, return the results, and Claude decides whether it has enough to answer or needs to search again. This agentic retrieval pattern handles multi-hop questions much better than a single fixed retrieval step. Details on defining and handling tools are in the tools docs.

Putting it behind one API key

If you're already calling the Anthropic API directly, this pattern works unchanged — just swap the endpoint. The reason teams route through SubToAPI instead is operational: one sub_live_ key across environments, usage metadata per request so you can see exactly how much your RAG pipeline is spending on generation, and team seats so multiple engineers aren't sharing one raw key. Embeddings and vector search stay entirely on your own infrastructure — SubToAPI only sits in front of the Claude generation calls. Start with the quickstart or sign up for a free trial to wire this into an existing pipeline.

Questions

Does Anthropic offer an embeddings API? No. Claude's API handles text generation, tool use, and streaming, but not embeddings. For vectors, use a dedicated embeddings model like Voyage AI, OpenAI, or Cohere.

Can I use Claude's hidden states as embeddings? Not through the public API — Anthropic doesn't expose intermediate activations. Even if it did, purpose-built embedding models consistently outperform generative models on retrieval benchmarks.

What's the simplest way to add semantic search to a Claude-powered app? Pick an embeddings provider, index your documents in a vector store, retrieve top matches per query, and pass them to Claude as context in a normal Messages request to generate the final answer.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →