LibrariEval System
LeaderboardDocsPricingSign UpLogin
Librari Evals — Docs

Call the Embed API

Turn batches of text into vector embeddings through the gateway with POST /api/embed — same key, error envelope, and cost reporting as the Extract API.

Need vectors for search or similarity over text you've already extracted? POST /api/embed takes up to 100 short texts and returns one embedding per text, in order, priced and logged like every other model call the gateway makes. It uses the same bearer key as the Extract API, the same error envelope, and the same usage / cost shape, so a client that already talks to /api/extract needs nothing new.

It is synchronous. A full batch completes in a second or two, so there is no submit-and-poll variant.

Before you call it

  • A bearer key from Manage Extraction API Keys. It's the same key /api/extract uses.
  • An embedding deployment id. Only deployments whose Modality is Embedding can serve this endpoint — see Chat vs embedding deployments. Today that's text-embedding-3-small on OpenAI and on Azure OpenAI. Copy the id from the deployment's admin page.
  • A provider key linked to that deployment for your tenant, set up under Manage LLM Provider API Keys. Until a key is linked, the endpoint answers model_unavailable.

Request

POST /api/embed
Authorization: Bearer <your tenant key>
Content-Type: application/json

{
  "modelDeploymentId": "6b4f…",            // required: an EMBEDDING model deployment
  "dimensions": 1536,                        // optional; defaults to the deployment's setting
  "inputs": [
    { "id": "3f2a…:0", "text": "This Master Services Agreement is entered into…" },
    { "id": "3f2a…:1", "text": "…continued text of the next window…" }
  ],
  "metadata": { "file_processing_id": "…" } // optional; stored on the usage-ledger row for tracing
}
FieldRule
modelDeploymentIdThe id of an embedding deployment. A chat deployment is rejected with deployment_modality_mismatch; an unknown, archived, or unlinked one with model_unavailable.
inputs1 to 100 items. Each text is non-empty and at most 32,000 characters (the model's limit is 8,191 tokens). Each id is an opaque string you use to match results, unique within the request, at most 256 characters.
dimensionsA positive integer no larger than the deployment's default (1,536 for text-embedding-3-small, which supports any smaller value natively — 512 is the other value we expect to use). Omit it to get the deployment's default.
metadataAny JSON object up to 4 KB. Echoed into the usage ledger, never sent to the provider.
Whole requestAll or nothing. If any input is invalid, nothing is embedded and the error names the offending index. Retry the whole batch; there are no partial results.

Response

{
  "success": true,
  "modelDeploymentId": "6b4f…",
  "deploymentName": "text-embedding-3-small",
  "provider": "OpenAI",
  "dimensions": 1536,
  "embeddings": [
    { "id": "3f2a…:0", "index": 0, "embedding": [0.0123, -0.0456, …] },
    { "id": "3f2a…:1", "index": 1, "embedding": [ … ] }
  ],
  "usage": { "inputTokens": 74210, "outputTokens": 0, "totalTokens": 74210 },
  "cost":  { "inputCost": 0.001484, "outputCost": 0, "totalCost": 0.001484,
             "inputPricePerMillion": 0.02, "outputPricePerMillion": 0 },
  "durationMs": 812
}
  • Order is input order, and every input gets exactly one entry. id and index both identify it.
  • Vectors are returned as the provider returns them — unit-normalised floats. The gateway doesn't normalise, quantise, or cache anything.
  • usage and cost use the same keys as the Extract API, so you can pass them straight into whatever already consumes extract results. outputTokens is always 0.
  • Size: 100 vectors of 1,536 floats is about 1.5 MB of JSON.

Errors

Same envelope as the Extract API. Branch on type and retryable, never on the message text.

{ "error": { "type": "invalid_request", "status": 400, "retryable": false,
             "message": "inputs[37].text must be a non-empty string.", "index": 37 } }
StatustyperetryableWhen
400invalid_requestnoMore than 100 inputs, empty text, over the character cap, duplicate ids, bad dimensions, oversized metadata, or a provider 400 (for example a single input over 8,191 tokens). index names the first offending input where one applies.
400deployment_modality_mismatchnomodelDeploymentId is a chat deployment. Carries expectedModality: "embedding" and actualModality: "chat".
401authnoMissing or rejected bearer key.
408timeoutyesThe request body did not fully arrive within 10 seconds. Nothing was parsed or sent. Resend.
413payload_too_largenoThe request body exceeded the gateway's byte ceiling (about 20 MB, sized so a full batch at the character cap always fits). Rejected while streaming, before anything is parsed. Send fewer or shorter inputs.
404model_unavailablenoNo enabled embedding deployment has that id, or no provider key is linked to it for your tenant.
429rate_limityesThe provider throttled the call. Retry-After is set.
502upstream_unavailableyesThe provider errored or was unreachable, or answered with an unusable payload (wrong vector count, malformed indexes, non-numeric or wrong-width vectors). Nothing was applied.
502authnoThe provider rejected our key for it — the linked provider key is revoked or wrong. Fix it under Manage LLM Provider API Keys.
502insufficient_creditsnoThe provider account is out of quota or billing.
503upstream_unavailableyesThe gateway's own catalog lookup failed (database outage or pool timeout). The model was never asked. Same type as the provider case above, so one retry branch covers both.
503at_capacityyesThis replica is already handling its maximum number of concurrent embed calls and fast-failed rather than queue yours. The model was never asked. It's the embedding twin of the Extract API's extract_at_capacity.
504timeoutyesThe provider call exceeded the gateway's 30-second budget.

If your client already retries 429, 502, 503, and 504 with backoff and honours retryable, nothing changes for this endpoint.

Limits and behaviour

  • Latency: dominated by the provider. A full batch of typical 750-token chunks completes in a few seconds. The gateway's provider timeout is 30 seconds; set your read timeout to 60.
  • Concurrency: per replica, up to 32 provider calls in flight (EMBED_MAX_CONCURRENCY) and up to 16 request bodies being received at once (EMBED_MAX_INGEST_CONCURRENCY); beyond either you get at_capacity and should retry. There is no per-tenant rate limit today.
  • Idempotent in effect: the same text, deployment, and dimensions return a vector you can treat as equivalent across calls. Bit-exactness is not promised — the provider doesn't promise it either.
  • Logging: one structured log line per request with tenant, deployment, input count, tokens, cost, and latency. Never the text.
  • Cost: every call, success or failure, writes a row to the usage ledger under operation Embed API, so it appears in Explore Costs alongside extractions.

Example

curl -sS https://evals.thelibrari.com/api/embed \
  -H "Authorization: Bearer $EVALS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "modelDeploymentId": "6b4f…",
    "dimensions": 512,
    "inputs": [{ "id": "c:0", "text": "This Master Services Agreement is entered into…" }]
  }'

On this page