Skip to content
Foldbun StackDocs
中Get an API keyComing soon

Embeddings and search

View as MarkdownTry in PlaygroundComing soon

Embeddings turn an image or a text into an L2-normalised vector. Vectors that point in similar directions describe similar content, which supports image-to-image similarity, near-duplicate detection, retrieval by example, text search over images and zero-shot classification against a list of labels. The endpoint returns vectors only: storing them and ranking by similarity is left to the caller. Vectors of different models are not comparable, so a collection indexed with one model is queried with the same model.

Each response carries dimensions (the length of every vector) and embeddings, an array with one entry per input. A vector is a plain JSON array of numbers (float32 values, not base64). Vectors come L2-normalised, so no further normalisation is needed: the cosine similarity of two inputs equals the dot product of their vectors, and a higher value means more similar. dimensions was 768 in the recorded responses; code should read the field and not hard-code the length.

siglip2: image-to-text scores are small numbers. In the recorded examples below, the best match scored 0.133 and unrelated pairs scored about 0. Only the ranking and the gaps between scores carry meaning, so scores are compared against each other for one query and no fixed cut-off is assumed.

Embed the query image and each candidate, then rank the candidates by dot product with the query. For large collections, keep the vectors on the client side and use a vector index; the endpoint returns embeddings only.

A red canvas sneaker as the query (image 0), compared with a close-up of a red sneaker (0.714), a white sneaker with black stripes (0.495) and a grey backpack (0.091), each with a bar for its score.

dinov3: recorded Playground result: cosine similarity of the query (image 0, blue outline) to three other images. The look-alike scores highest, a different sneaker lies in the middle and an unrelated object scores near zero.

Copies of the same picture (re-encoded, resized or lightly edited) are expected to score far higher against the original than unrelated images do, so a similarity threshold turns the same call into a de-duplication filter. The API gives no recommended threshold; pick one on a labelled sample of the collection. For retrieval by example, embed the query once, compare it with the stored vectors and return the highest scores.

Embed each image once (one call per image) and keep the vectors. To search, embed the query text with one texts call and rank the images by dot product. A text-only call has no image in its response.

The query “a bowl of ramen” above three photos: a bowl of ramen (0.133, highlighted), a rainy street at night (0.000) and a dog lying on sand (-0.002), each with a score bar.

siglip2: recorded Playground result: one text query scored against three images. The ramen photo ranks first; the other two score about 0.

Embed one image and a list of candidate labels (up to 64 per call), then rank the labels by dot product with the image. The top label is the prediction. The labels are ordinary texts, so they can be changed per request without retraining.

A photo of a bowl of ramen with a side dish, next to five ranked labels: “a bowl of ramen” 0.133 (highlighted), a Chinese label for a bowl of ramen 0.108, “a cup of coffee” 0.055, “a salad” 0.035 and “a pizza” 0.017.

siglip2: recorded Playground result: one image scored against five labels. The matching label ranks first, and the same dish described in Chinese also ranks second.

dinov3 siglip2
Model DINOv3 ViT-B/16 SigLIP 2 base, patch 16, 224 px
Accepts One image One image, or 1 to 64 texts of 1 to 1000 characters, never both
Returns One purely visual vector per image One vector per image or text, in one shared space
List price (credits) 0.05 per image 0.05 per image, 0.01 per text
Pool Public: available to every registered account, 100 calls per UTC day included Public: available to every registered account, 100 calls per UTC day included
Vector length 768 in the recorded responses; read dimensions 768 in the recorded responses; read dimensions
Recorded processing time 216 ms (one recorded call) About 200 ms
Attribution “Built with DINOv3” None
Pick when The query is an image The query is a sentence or a set of labels, or texts and images are compared
  • Pick dinov3 for image-to-image similarity, de-duplication and retrieval by example (“find images like this one”).
  • Pick siglip2 for text search over images, zero-shot classification, and any case where a text and an image are compared with each other.

One image of the first figure, embedded with dinov3:

curl https://api.stack.foldbun.com/v1/embeddings \
-H "Authorization: Bearer $FOLDBUN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "dinov3",
"image": { "id": "img_36aec8cbc5b68661a926869a8bc8aa79de584edbb2aec2454bd1f1c169af09d7" }
}'

The response is abridged: the vector is shortened.

{
"id": "call_01a1913e-868a-7d5a-841c-5913396a9ea1",
"model": "dinov3",
"image": {
"id": "img_36aec8cbc5b68661a926869a8bc8aa79de584edbb2aec2454bd1f1c169af09d7",
"width": 1512,
"height": 1008,
"bytes": 342140,
"contentType": "image/jpeg"
},
"dimensions": 768,
"embeddings": [
{ "index": 0, "vector": [-0.007488, -0.036278, -0.000432] }
],
"cost": 0.05,
"balance": 12.45,
"timing": { "queueMs": 0, "processingMs": 216 },
"billing": {
"lines": [
{ "unit": "image", "quantity": 1, "unitPrice": 0.05, "amount": 0.05, "waived": false }
],
"total": 0.05,
"charged": true,
"pool": null
}
}
  • dimensions is 768: every vector has that length. Code should read the field and not hard-code the length.
  • embeddings[0] has index 0 and vector, the L2-normalised float32 values (3 of 768 shown). index is the position in texts, or 0 for an image.
  • A text-only siglip2 call returns one entry per text, in input order, and no image.

The cosine similarity of two vectors from the same model is their dot product:

def cosine(a: list[float], b: list[float]) -> float:
return sum(x * y for x, y in zip(a, b))

The two vectors come from two calls with the same model, one call per image.

All fields: API reference.

Cost of this call. 0.05 (image) credits, as charged in this response. With siglip2, an image is also 0.05 and each text 0.01, so the three labels of the flow below cost 0.03. Unit prices: Billing.

The complete flow in Python, with the image and the labels in two calls:

import os
import requests
API = "https://api.stack.foldbun.com/v1/embeddings"
HEADERS = {"Authorization": f"Bearer {os.environ['FOLDBUN_API_KEY']}"}
def embed(**body):
r = requests.post(API, headers=HEADERS, json={"model": "siglip2", **body}, timeout=60)
r.raise_for_status()
return [e["vector"] for e in r.json()["embeddings"]]
texts = ["a bowl of ramen", "a pizza", "a salad"]
image_vec = embed(image={"id": "img_f4e4f5a8a14f25689a345acf67ea1a83c5760e219c0dcf5255717cdb9bd5e225"})[0]
scores = [sum(a * b for a, b in zip(image_vec, v)) for v in embed(texts=texts)]
for text, score in sorted(zip(texts, scores), key=lambda p: -p[1]):
print(f"{score:.3f} {text}")
Endpoint In this use case Reference
POST /v1/embeddings One vector per image, or per text with siglip2, in input order API reference
  • dinov3 and siglip2: how each model works, its limits and measured latency.
  • Billing: image for both models, text for siglip2 only.
  • Attribution: the “Built with DINOv3” tag for products built on dinov3.