Back to blog

OpenAI Embeddings API: The Complete Developer Reference

Master the OpenAI Embeddings API with this developer reference covering endpoints, models, code samples, cost trade-offs, debugging tips, and real integration

OpenAI Embeddings API: The Complete Developer Reference

You inherit a folder of legacy PDF contracts and need to find clauses similar to the payment terms in a recent vendor agreement. A keyword search misses the matches because one document says “payment terms” and another says “billing schedule.” The OpenAI Embeddings API solves this by representing text as vectors that capture meaning, giving document systems a practical foundation for semantic search, deduplication, clustering, and retrieval-augmented generation.

What the OpenAI Embeddings API Actually Does

The OpenAI Embeddings API is a hosted endpoint that converts text into a dense numerical vector. Each vector contains floating-point values representing the semantic characteristics of the input. Texts with related meanings tend to occupy nearby positions in vector space, and OpenAI documents that smaller vector distances indicate higher semantic relatedness. See the official embeddings guide for the documented retrieval pattern.

A typical workflow is straightforward:

  1. Send a string to /v1/embeddings.
  2. Receive a fixed-length array of floating-point values.
  3. Store that vector with the source text and metadata.
  4. Embed a user query at runtime.
  5. Search for nearby vectors with a vector database or similarity function.

The model doesn't require exact word matches. “Payment terms” and “billing schedule” can be treated as related concepts because the embedding represents their meaning rather than only their spelling. Current models commonly produce 1,536 or 3,072 dimensions, depending on the selected model and configuration. Those values come from OpenAI's model specifications, not from the document text itself.

Practical rule: Store the original text, document identifier, chunk identifier, model name, and embedding together. A vector without its provenance is difficult to audit or rebuild.

Embeddings are stateless. The endpoint has no conversation history, system prompt, or chat session. You send text for encoding, which makes the operation easy to cache and batch. The resulting vectors form the indexing layer underneath semantic search, near-duplicate detection, topic clustering, recommendations, and RAG systems.

A Short History of the Embeddings Endpoint

OpenAI first introduced embeddings as a product feature on January 25, 2022, with its announcement of text and code embeddings. That launch established /embeddings as a dedicated API primitive for turning text into vectors used in semantic search, clustering, and retrieval workflows.

The product line later changed substantially. On January 25, 2024, OpenAI announced new embedding models and API updates, introducing text-embedding-3-small and text-embedding-3-large. The release gave developers a clearer choice between a lower-cost model and a larger model with more dimensions by default.

The older ada-era approach remains relevant when you inherit an existing index, but new systems should treat model selection as an architectural decision. An index built with one model can't safely accept vectors from another without a deliberate migration and re-indexing plan.

A timeline graphic showing the historical evolution of OpenAI embedding models from December 2022 to the present.

The important historical shift is practical rather than cosmetic. Embeddings moved from a specialized API feature into a standard building block for search and classification applications. That makes the endpoint useful even when it isn't directly connected to a chat model.

Choosing the Right Embedding Model

The production choice usually comes down to text-embedding-3-small, text-embedding-3-large, or compatibility with an existing text-embedding-ada-002 index. The current v3 models support dimension control, while ada-002 is fixed at 1,536 dimensions, as documented in OpenAI's model and API materials.

Model Dimensions Price per 1M tokens Best for
text-embedding-3-small 1,536 by default, configurable lower dimensions $0.02 High-volume indexing and cost-sensitive retrieval
text-embedding-3-large 3,072 by default, configurable lower dimensions $0.13 Retrieval where quality is the primary constraint
text-embedding-ada-002 1,536 fixed Pricing should be checked for the inherited deployment Existing indexes and migration compatibility

The price difference is significant. text-embedding-3-small costs $0.02 per 1 million input tokens, while text-embedding-3-large costs $0.13 per 1 million input tokens, according to OpenAI's embedding model announcement. The large model produces twice as many dimensions as the small model by default, which generally means more vector storage and computation.

Start with small when you need to index large document collections, especially if your evaluation set shows acceptable recall after dimension reduction. Choose large when missed retrievals are expensive, documents contain subtle distinctions, or multilingual and domain-specific queries expose weaknesses in the smaller model.

Decision rule: Begin with text-embedding-3-small and a reduced dimension such as 1,024, then move to text-embedding-3-large only when measured retrieval quality justifies the additional token and storage cost.

Don't mix models in one vector index. Cosine scores between vectors generated by different embedding models aren't meaningful, even when the arrays happen to have compatible lengths. Teams evaluating Hugging Face API integrations should apply the same rule to hosted or open-source alternatives.

Endpoint Reference and Core Parameters

The endpoint is a POST request to Authentication uses an API key in theAuthorization' header.

The request fields developers usually touch are:

  • model identifies the embedding model, such as text-embedding-3-small.
  • input accepts a string or an array of strings or tokens.
  • encoding_format accepts float or base64. Float output is convenient for application code, while base64 can reduce response payload size during large backfills.
  • dimensions requests a smaller vector on supported v3 models.
  • user is an optional identifier that can help associate requests with an application user for abuse monitoring.

OpenAI documents an input limit of 8,192 tokens for the current embedding models. A request can contain multiple inputs, but each item still needs to fit within the model's limit. Treat input size as a validation concern before making the network call.

A representative request looks like this:

{
  "model": "text-embedding-3-small",
  "input": ["payment terms", "billing schedule"],
  "encoding_format": "float",
  "dimensions": 1024
}

The response contains an object, a data array, and usage. Each data item includes an index, an embedding array, and its object type. Usage exposes prompt_tokens and total_tokens, which should be logged for cost analysis.

For multi-tenant accounts, project-scoped deployments may also use OpenAI-Organization and OpenAI-Project headers. Keep credentials server-side, never expose them in browser JavaScript, and validate response lengths before writing vectors to the database.

Working Code Samples in Python, JavaScript, and cURL

The following examples send the same two inputs to the same endpoint. They assume the API key is available in an environment variable named OPENAI_API_KEY.

Python

import os
from openai import OpenAI

client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])

response = client.embeddings.create(
    model="text-embedding-3-small",
    input=["payment terms", "billing schedule"],
    encoding_format="float",
)

for item in response.data:
    print(item.index, item.embedding[:8])

print(response.usage)

The official Python SDK returns floating-point values by default. Pin the SDK version in your dependency file so an upgrade doesn't alter serialization or response handling.

JavaScript

import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

const { data, usage } = await client.embeddings.create({
  model: "text-embedding-3-small",
  input: ["payment terms", "billing schedule"],
  encoding_format: "float",
});

for (const item of data) {
  console.log(item.index, item.embedding.slice(0, 8));
}

console.log(usage);

The Node client parses the JSON response for you. If your application uses base64 responses, verify the behavior of the exact SDK version you're running instead of assuming every client handles decoding identically.

cURL

curl https://api.openai.com/v1/embeddings \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "text-embedding-3-small",
    "input": ["payment terms", "billing schedule"],
    "encoding_format": "base64"
  }' | jq '.data[0]'

cURL exposes the wire format directly. With base64, your application must decode the returned representation before calculating similarity or inserting values into a vector store. Use float output while debugging, then consider base64 for bandwidth-sensitive bulk operations.

Cost, Storage, and Latency Trade-offs

Embedding spend has three separate components: token fees, vector storage, and request overhead. Focusing only on the API invoice can hide the cost of keeping large arrays in indexes, replicating them, and scanning them during retrieval.

OpenAI lists text-embedding-3-small at $0.02 per 1 million input tokens and text-embedding-3-large at $0.13 per 1 million input tokens in its pricing and model update. Your token bill depends on the text you send, so remove repeated headers, navigation, and OCR noise before embedding.

A rough storage model is:

number of vectors × dimensions × 4 bytes

That assumes float32 storage. Lower dimensions reduce storage and index work, but they can also reduce retrieval quality. The right setting depends on your evaluation results, not on the smallest possible array.

A comparison chart highlighting the cost, vector storage dimensions, and request latency for OpenAI embedding models.

Model total cost with a simple checklist:

  • Token spend: total input tokens multiplied by the selected model's price.
  • Storage spend: vector count multiplied by dimensions and bytes per value.
  • Operational spend: request count, retries, queueing, and database index maintenance.
  • Quality cost: missed matches, irrelevant context, and human review caused by weak retrieval.

For most document pipelines, small with reduced dimensions is a sensible baseline. Large belongs in the measured exception category, where retrieval quality is a proven bottleneck rather than an assumption.

A practical visual comparison can help teams align engineering and finance decisions:

Similarity Metrics and Vector Store Options

Cosine similarity is the usual starting point for semantic retrieval because it compares vector direction rather than raw magnitude. OpenAI describes smaller vector distances as stronger semantic relatedness in its embeddings documentation. Dot product can work well when vectors are normalized, while Euclidean distance remains useful when your store or scoring design depends on absolute geometric distance.

Option Type Best for Notes
pgvector PostgreSQL extension Teams already using PostgreSQL Keeps vectors and relational metadata together
Pinecone Managed vector database Managed production retrieval Convenient scaling and filtering
Weaviate Managed or self-hosted vector database Search platforms needing rich schema features Supports metadata-aware retrieval
Qdrant Self-hosted or managed vector database Operational control Strong filtering and deployment flexibility
FAISS In-memory library Local experiments and prototypes You must build persistence and metadata handling

The store should match the metric. Configure the index dimension to exactly match the embedding output, then choose HNSW or IVF based on operational requirements and evaluation results. Metadata filters matter just as much as vector distance for business documents, where tenant, document type, vendor, invoice status, and access permissions must constrain retrieval.

A PostgreSQL team may prefer Elasticsearch Python API integration when keyword, metadata, and semantic retrieval need to coexist. For a broader explanation of understanding search retrieval methods, compare lexical search and vector retrieval before committing to a single search architecture.

Chunking and Preprocessing Long Documents

Long documents should be split before embedding. OpenAI's guidance recommends pre-chunking source content below the token limit, embedding each chunk, and storing those vectors for nearest-neighbor lookup. A chunk should represent a coherent idea, clause, table, or section, not an arbitrary slice of characters.

A reliable preparation sequence is:

  1. Remove repeated headers, footers, navigation text, and OCR artifacts.
  2. Split first at document structure, such as headings and paragraphs.
  3. Split oversized paragraphs at sentence boundaries.
  4. Preserve identifiers and page references as metadata.
  5. Embed each final chunk and keep the source text beside the vector.

Use a tokenizer such as tiktoken to count tokens accurately. Character counts are only a rough proxy and drift across languages, punctuation, tables, and OCR output. Libraries such as LangChain splitters, LlamaIndex node parsers, and custom spaCy pipelines can provide a starting point, but the correct boundary is the one that preserves retrieval meaning.

A diagram illustrating a five-step process for chunking and preprocessing long documents for better retrieval quality.

For invoices and contracts, preserve the fields that users search for. A chunk containing a payment clause should retain nearby conditions, exceptions, and section labels. Guidance on how to split PDF documents is useful when a single upload contains several document types or unrelated pages.

Don't optimize chunk size in isolation. Evaluate whether the retrieved passage answers the query, then adjust boundaries, overlap, metadata, and dimensions together.

Pairing OpenAI Embeddings With Matil.ai Output

Raw OCR text is often a poor embedding input. It can contain broken reading order, duplicated labels, missing table relationships, and inconsistent formatting. A document extraction platform such as Matil.ai can first convert invoices, delivery notes, contracts, and other files into structured JSON with normalized fields and clean text, then OpenAI embeddings can index the result.

A production flow looks like this:

  1. Upload the PDF or image to Matil.ai.
  2. Receive extracted fields such as vendor, line items, totals, and full text.
  3. Build embedding text from the clean narrative and selected fields.
  4. Store the vector with metadata such as document type, vendor, invoice number, and date.
  5. Query the vector index while applying permission and business filters.

This separation improves retrieval design. Structured values remain filterable, while the embedding handles paraphrases and semantic intent. An invoice number shouldn't depend on vector similarity alone, and a query such as “late delivery surcharge” shouldn't require an exact phrase match.

A compact Python sketch might look like this:

from openai import OpenAI

client = OpenAI()

def build_embedding_input(document):
    fields = [
        document.get("document_type", ""),
        document.get("vendor", ""),
        document.get("invoice_number", ""),
        document.get("full_text", ""),
    ]
    return "\n".join(value for value in fields if value)

def embed_documents(documents):
    texts = [build_embedding_input(doc) for doc in documents]
    response = client.embeddings.create(
        model="text-embedding-3-small",
        input=texts,
        dimensions=1024,
    )

    records = []
    for document, item in zip(documents, response.data):
        records.append({
            "id": document["id"],
            "values": item.embedding,
            "metadata": {
                "document_type": document.get("document_type"),
                "vendor": document.get("vendor"),
                "invoice_number": document.get("invoice_number"),
            },
        })
    return records

The vector write is intentionally omitted because pgvector, Pinecone, Qdrant, and other stores use different clients. Keep the extraction response and embedding request traceable through a shared document identifier.

Building Search, Deduplication, Clustering, and RAG

The same vector representation supports several workflows, but each requires a different evaluation method.

Pattern Similarity threshold Best use case
Semantic search Tune against labeled queries Finding relevant clauses, invoices, or policies
Deduplication Set from validation data Flagging near-identical tickets or documents
Clustering No fixed threshold Surfacing topics without labels
RAG Tune retrieval depth and relevance Supplying grounded passages to a generation model

For semantic search, embed the user's query with the same model used for indexing, then retrieve the nearest chunks:

query_vector = client.embeddings.create(
    model="text-embedding-3-small",
    input="Which suppliers have extended payment terms?"
).data[0].embedding

results = vector_store.search(query_vector, top_k=5)

For deduplication, compare candidate pairs rather than every document against every other document. Store invoice numbers, vendor identifiers, and source hashes as additional signals. A vector match can flag a review candidate, but it shouldn't automatically merge legally or financially meaningful records without validation.

Clustering can reveal recurring document families:

from sklearn.cluster import KMeans

vectors = [record["values"] for record in records]
labels = KMeans(n_clusters=5, random_state=0).fit_predict(vectors)

The cluster count is an application choice. Inspect representative documents before naming a group or triggering automation.

RAG adds one more step. Retrieve relevant chunks, pass their text and structured metadata to the generation model, and retain source identifiers for citations. Matil.ai output can supply reliable fields such as invoice numbers and line items alongside the retrieved passages, allowing filters to narrow the search before semantic ranking.

Common Pitfalls and How to Debug Them

Embedding systems often fail without notice. The API call succeeds, vectors reach the database, and retrieval quality deteriorates without an obvious exception.

A graphic titled Common Embeddings Pitfalls and Fixes listing three key mistakes and solutions for vector embeddings.

Check these failure modes first:

  • Mixed models: Writing vectors from different models into one index makes similarity scores unreliable. Include the model name in each record and rebuild the index when migrating.
  • Wrong normalization: Dot-product stores may require L2-normalized vectors. Confirm the store's metric and normalization behavior before indexing.
  • Oversized input: Count tokens before the request and split content that exceeds the model limit. Don't rely on character length.
  • Deprecated identifiers: Keep model names in configuration rather than scattering them through application code. A central setting makes migrations manageable.
  • Aggressive batching: Large batches can hit token-per-minute or request limits. Reduce batch size, add exponential backoff, and make writes idempotent.
  • Missing version metadata: Persist the model, dimensions, preprocessing version, and timestamp with the index manifest. Otherwise, reproducing an old result becomes guesswork.
  • Empty content: Skip empty strings and documents that contain no usable text. A successful response doesn't make an empty source useful.

Debugging sequence: Reproduce the request locally, verify token counts with tiktoken, inspect vector length and magnitude, then compare the response object with the documented JSON shape.

Log request identifiers, batch boundaries, retry decisions, and database write outcomes. For backfills, use deterministic vector IDs so a retry overwrites the intended record instead of creating duplicates.

Quick Reference Checklist and FAQ

Before launching an embeddings pipeline, confirm the operational details:

  • Model: Select one model and record its exact identifier.
  • Dimensions: Match the vector-store index to the requested output size.
  • Tokens: Count and validate every chunk before sending it.
  • Metric: Choose cosine, dot product, or Euclidean distance deliberately.
  • Normalization: Apply it only when required by the selected metric and store.
  • Retries: Handle transient failures and rate-limit responses with backoff.
  • Batching: Load-test realistic input sizes and request concurrency.
  • Provenance: Persist source text, metadata, model, dimensions, and preprocessing version.
  • Evaluation: Test retrieval with representative business queries before indexing the full corpus.

Can you switch from small to large without re-indexing

No. The vectors come from different model spaces, and their default dimensions differ. Generate new vectors for both stored documents and runtime queries before switching the production index.

How should you reduce dimensions

Use the dimensions parameter on supported v3 models. The API returns the shorter vector, but reducing dimensions can discard information, so validate recall and ranking quality against your own queries.

Are embeddings multilingual

The v3 models support multilingual semantic similarity. Test the languages, abbreviations, document layouts, and terminology that matter to your organization rather than assuming English evaluation results transfer perfectly.

How do you test retrieval offline

Create a labeled set of queries and relevant documents, then measure whether the correct passages appear near the top of results. Include paraphrases, identifiers, multilingual queries, and difficult edge cases from finance, logistics, legal, or compliance workflows.

Choose the smallest model that meets your recall target, and version everything from preprocessing through vector storage.


Matil.ai combines advanced OCR, classification, validation, and workflow automation to turn PDFs and images into structured JSON that is ready for downstream search and RAG pipelines. If you want to connect reliable document extraction with OpenAI embeddings, explore Matil and evaluate the workflow against your own invoices, contracts, KYC files, or logistics documents.

Related articles

© 2026 Matil