plaingateway
API reference

Embeddings

Turn text into vectors with POST /embeddings, the same request and answer as OpenRouter's.

POST /embeddings turns text into vectors: lists of numbers that sit close together when the texts mean similar things. Use them for search, retrieval for a chat model, clustering and finding duplicates. The request and the answer have the same shape as OpenRouter's and OpenAI's, so an OpenAI SDK works with only the base URL and the key changed. You pay for input tokens only. The answer carries the charge in usage.cost.

Request

text
POST https://api.plaingateway.com/api/v1/embeddings
Authorization: Bearer $PLAINGATEWAY_API_KEY
Content-Type: application/json
Field Type Required What it does
model string yes An embedding model id, such as openai/text-embedding-3-small. See Models.
input string or array yes The text or tokens to embed, in one of the five forms below.
dimensions integer no How many numbers each vector has. Only text-embedding-3-small and text-embedding-3-large take it.
encoding_format string no float (the default) returns arrays of numbers. base64 returns each vector as a base64 string of 32-bit floats, which is smaller.
input_type string no What the input is, such as search_query or search_document. Accepted. The OpenAI and Azure hosts do not take it, so it is not sent to them.
user string no Your end user's id. It is stored as external_user on the generation.
provider object no Which hosts may serve the request and in what order. See Provider routing.
session_id string no Accepted and not stored. It never reaches the host.
trace object no Accepted and not stored. It never reaches the host.

stream is ignored: the answer is always one JSON body. models is ignored too, so model is required.

The five forms of input

Form Example
A string "input": "The cat sat on the mat"
An array of strings "input": ["The cat sat", "A dog ran"]
One array of token ids "input": [791, 8415, 7731]
An array of token id arrays "input": [[791, 8415], [32, 5679]]
An array of content objects "input": [{"content": [{"type": "text", "text": "The cat sat"}]}]

A content object may hold only text parts; its text is sent to the host as a string. An image or any other part returns 400, because no listed model takes images. Strings must not be empty, and token arrays must hold at least one token.

Response

One data item for each input, in the order you sent them. index is the input's position. model is the host's own model name, without the openai/ prefix, as on OpenRouter. id has the form gen-emb-<unix seconds>-<20 letters and digits>; pass it to GET /generation to read the request back. usage.cost is the charge in USD. prompt_tokens and total_tokens are the same number, since there are no output tokens. The X-PG-Host and X-PG-Cost-USD headers carry the host and the charge, as on every non-streamed answer. See Headers.

http
HTTP/1.1 200
{
  "object": "list",
  "data": [
    {
      "object": "embedding",
      "embedding": [0.016754150390625, -0.055755615234375, 0.005634307861328125],
      "index": 0
    }
  ],
  "model": "text-embedding-3-small",
  "usage": {
    "prompt_tokens": 1,
    "total_tokens": 1,
    "cost": 2e-08,
    "is_byok": false,
    "cost_details": {
      "upstream_inference_cost": 2e-08,
      "upstream_inference_prompt_cost": 2e-08,
      "upstream_inference_completions_cost": 0
    }
  },
  "provider": "OpenAI",
  "id": "gen-emb-1794367041-trccdd4mAq6ZFMp5X8f0"
}

This is a recorded answer with the vector shortened; a real one has 1,536 numbers for text-embedding-3-small. Your usage.cost is the charge at our price.

Errors

Errors have the shape described in Errors. These are the ones particular to embeddings:

Status When Message
400 The model is unknown, or is not an embedding model Model <id> does not exist
400 input is an empty array Input is empty
400 input is missing, an empty string, or holds an empty string, an empty token array or a non-text part A message naming the problem
400 More than 2,048 inputs, refused before any host HTTP 400: ... holding array length must be 2048 or less
400 One input is over 8,192 tokens HTTP 400: ... holding the host's message, maximum context length is 8192 tokens
401 No key, or a key that is unknown, disabled, expired or revoked
402 The balance cannot cover the request, or the key reached its spend limit
404 The provider filters leave no host
429 The host rate limited the request
502 The host failed, or its answer was over the request's size cap
503 Another request with a large answer is being read; see Limits the gateway is busy with other large answers; try again shortly

A chat model sent here gets the first 400. An embedding model sent to /chat/completions or another chat endpoint gets that endpoint's unknown model 400. An error before the host answered is not charged. Once the host has answered, the request is charged even if the answer cannot be delivered, because the host was paid; see Errors.

Limits

  • At most 2,048 inputs in one request.
  • At most 8,192 tokens in each input.
  • No streaming.
  • A large answer is served one at a time. The gateway sizes each answer from the number of inputs and the numbers in each vector: dimensions, or 3,072 when you name none. When that size could pass 32 MB and another such answer is being read, the request gets 503 at once, before any charge. With float vectors that is more than 310 inputs, or more than 619 with dimensions at 1,536; with base64 (the OpenAI SDK's default) it is more than 1,953 inputs. Split a larger batch, or retry the 503 after a short wait.
  • The same input gives the same vector each time, so store vectors instead of asking again.

Examples

curl

sh
curl https://api.plaingateway.com/api/v1/embeddings \
  -H "Authorization: Bearer $PLAINGATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "openai/text-embedding-3-small", "input": ["The cat sat on the mat", "A dog ran in the park"]}'

Python (OpenAI SDK)

python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.plaingateway.com/api/v1",
    api_key=os.environ["PLAINGATEWAY_API_KEY"],
)
r = client.embeddings.create(
    model="openai/text-embedding-3-small",
    input=["The cat sat on the mat", "A dog ran in the park"],
)
print(len(r.data), len(r.data[0].embedding))  # 2 1536

TypeScript (OpenAI SDK)

typescript
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.plaingateway.com/api/v1",
  apiKey: process.env.PLAINGATEWAY_API_KEY,
});
const r = await client.embeddings.create({
  model: "openai/text-embedding-3-small",
  input: ["The cat sat on the mat", "A dog ran in the park"],
});
console.log(r.data.length, r.data[0].embedding.length); // 2 1536

The OpenAI SDK asks for base64 by default and decodes it, so you get arrays of numbers either way.

Models

Model id Numbers in a vector
openai/text-embedding-3-small 1,536, or fewer with dimensions
openai/text-embedding-3-large 3,072, or fewer with dimensions
openai/text-embedding-ada-002 1,536

Their prices are on Models, per 1M input tokens. To list them from code, call GET /embeddings/models or GET /models?output_modalities=embeddings. The plain GET /models leaves them out, as OpenRouter's does.

Differences from OpenRouter

  • Only the OpenAI embedding models in the table above are served.
  • No batch API and no :batch models.
  • No image or other multimodal input.
  • A request whose answer could pass 32 MB is served one at a time; another such request gets 503 until the first ends. OpenRouter states no such limit.
  • In provider, require_parameters, preferred_max_latency, preferred_min_throughput, enforce_distillable_text and options are accepted and have no effect.
  • session_id and trace are accepted and not stored. GET /generation returns session_id as null.