GOPURA

Embeddings

OpenAI-compatible embeddings under the same wallet — semantic search, RAG, and clustering with in-band cost.

POST /v1/embeddings turns text into vectors for semantic search, RAG, recommendations, deduplication, and clustering. It is wire-identical to the OpenAI Embeddings API, so the SDK works with just the base URL swap — and as everywhere on Gopura, the exact billed cost rides in the response.

Already using OpenAI embeddings? Nothing needs re-embedding. openai/text-embedding-3-small, openai/text-embedding-3-large and openai/text-embedding-ada-002 are all served here, at their native dimensions, so an existing index stays valid and the migration really is just the base URL. Twenty-six embedding models are available in total — see the table below.

from openai import OpenAI

client = OpenAI(base_url="https://api.gopura.net/v1", api_key=GOPURA_API_KEY)

result = client.embeddings.create(
    model="alibaba/qwen3-embedding-0.6b",
    input=["the gopuram rises over the temple", "an unrelated sentence"],
)
print(len(result.data), "vectors")
print(result.usage)  # prompt_tokens + cost, in-band
curl https://api.gopura.net/v1/embeddings \
  -H "Authorization: Bearer $GOPURA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "alibaba/qwen3-embedding-0.6b", "input": "the gopuram rises"}'

Request

FieldTypeNotes
modelstringany embedding model from the catalog
inputstring or string[]up to 2,048 items / 1M characters total
encoding_format"float" | "base64"optional, passed through
dimensionsintoptional — only on models marked adjustable below; see the warning there

Response

The OpenAI shape, plus usage.cost:

{
  "object": "list",
  "data": [{ "object": "embedding", "index": 0, "embedding": [0.0123, …] }],
  "model": "alibaba/qwen3-embedding-0.6b",
  "usage": { "prompt_tokens": 8, "total_tokens": 8, "cost": 0.0000002 }
}

Embeddings bill on input tokens only, at the rate shown per model in the catalog (margin included; the figure matches usage.cost exactly).

Models and dimensions

Every model carries modality and its measured vector geometry in the live catalog, so you can size a vector column before indexing anything:

curl -s https://api.gopura.net/v1/models \
  | jq '.data[] | select(.modality == "embedding") | {id, embedding, pricing}'
{
  "id": "openai/text-embedding-3-small",
  "embedding": { "dimensions": 1536, "dimensions_adjustable": true },
  "pricing": { "prompt": "0.000000025", "completion": "0" }
}

dimensions_adjustable: false means the model returns its native width no matter what you ask for. Most such models do not error when you send dimensions — they accept it and return the full-width vector anyway, so a column sized from the value you requested will not match what arrives. Only openai/text-embedding-ada-002 fails loudly, with a 400. Check this field rather than assuming; dimensions appears in a model's supported_parameters only where it is genuinely honored.

ModelDimensionsdimensions adjustableInput /M
alibaba/qwen3-embedding-0.6b1024yes$0.0125
alibaba/qwen3-embedding-4b2560yes$0.025
alibaba/qwen3-embedding-8b4096yes$0.0625
amazon/titan-embed-text-v21024yes$0.025
cohere/embed-v4.01536yes$0.15
google/gemini-embedding-0013072yes$0.1875
google/gemini-embedding-23072yes$0.25
google/text-embedding-005768yes$0.03125
google/text-multilingual-embedding-002768yes$0.03125
mistral/codestral-embed1536no$0.1875
mistral/mistral-embed1024no$0.125
openai/text-embedding-3-large3072yes$0.1625
openai/text-embedding-3-small1536yes$0.025
openai/text-embedding-ada-0021536no$0.125
perplexity/pplx-embed-v1-0.6b1024no$0.005
perplexity/pplx-embed-v1-4b2560no$0.0375
voyage/voyage-3-large1024no$0.225
voyage/voyage-3.51024no$0.075
voyage/voyage-3.5-lite1024no$0.025
voyage/voyage-41024no$0.075
voyage/voyage-4-large1024no$0.15
voyage/voyage-4-lite1024no$0.025
voyage/voyage-code-21536no$0.15
voyage/voyage-code-31024no$0.225
voyage/voyage-finance-21024no$0.15
voyage/voyage-law-21024no$0.15

Dimensions are measured, not taken from vendor documentation: each model is embedded and the returned vector length recorded. Cheap bulk pick: perplexity/pplx-embed-v1-0.6b ($0.005/M) or alibaba/qwen3-embedding-0.6b ($0.0125/M). Highest quality: google/gemini-embedding-001, cohere/embed-v4.0 or the voyage/* family. Sending a chat model here (or an embedding model to /v1/chat/completions) returns a 400 naming the right endpoint.

Sizing a bulk indexing job

Three limits govern how fast a corpus can be indexed:

LimitValueOn exceeding
Items per request2,048400 invalid_request
Characters per request1,000,000 total400 invalid_request
Requests per minuteyour key's rpm_limit (default 600)429 rate_limited + Retry-After
Concurrent requestsyour key's concurrency_limit (default 30)429 too_many_concurrent

Read the two key limits rather than assuming them — they are per key, and yours may have been raised:

curl -s https://api.gopura.net/v1/key -H "Authorization: Bearer $GOPURA_API_KEY"

A practical shape for a large corpus: batch 100–200 chunks per request (well inside both caps, and large enough that per-request overhead disappears), run 8–16 requests concurrently, and honour Retry-After on 429 rather than retrying immediately. Embedding models whose upstream publishes no context window are listed at a conservative 8,192-token floor — that is a documented safe floor for batching, not a measured ceiling, so a model may accept more.

Every response carries its exact cost in usage.cost, so a job's true spend is the sum of what you already received — no reconciliation pass needed.