Everything you need to call the chat, embeddings, and image generation endpoints.
Authenticate every request with a bearer API key in the Authorization header. Keys are secret — the raw value is shown only once, when you create or rotate a key.
Create and manage keys under Settings → API Keys.
Authorization: Bearer wba_live_xxxxxxxxxxxxxxxxxxxxxxxxBase URL: https://api.webanto.com/api/v1
Five models across three scopes. Chat is multimodal; embeddings cover text and images; images are generated from text.
| Model | Endpoint | Kind | Scope |
|---|---|---|---|
| qwen | /api/v1/chat | Chat — multimodal (text + vision) | chat |
| nomic-embed-text | /api/v1/embeddings | Text embeddings | embeddings |
| clip | /api/v1/embeddings | Text + image embeddings — 512-d, shared space (cross-modal) | embeddings |
| dinov3 | /api/v1/image-embeddings | Image embeddings — 1280-d, L2-normalized | embeddings |
| flux.2-dev | /api/v1/images | Image generation — FLUX.2-dev text-to-image | images |
| birefnet-general | /api/v1/images/remove-background | Background removal — BiRefNet cutout on a solid white background | images |
Generate text embeddings with nomic-embed-text or clip. Requires a key scoped for embeddings.
POST /api/v1/embeddings
Request
curl https://api.webanto.com/api/v1/embeddings \
-H "Authorization: Bearer $WEBANTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "nomic-embed-text",
"input": ["a photo of a cat", "a photo of a dog"]
}'Response
{
"model": "nomic-embed-text",
"data": [
{ "index": 0, "embedding": [0.0123, -0.0456, "..."] },
{ "index": 1, "embedding": [0.0789, -0.0012, "..."] }
],
"usage": { "total_tokens": 14 },
"credits": 1
}Embed images with DINOv3 (1280-dimensional, L2-normalized). Send urls or images (not both), up to 60 per batch; URLs must be https. Requires a key scoped for embeddings.
POST /api/v1/image-embeddings
Request
curl https://api.webanto.com/api/v1/image-embeddings \
-H "Authorization: Bearer $WEBANTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "urls": ["https://cdn.example.com/card.jpg"] }'Response
{
"model": "dinov3",
"dim": 1280,
"embeddings": [[0.009, -0.002, "..."]],
"errors": [],
"credits": 1
}Generate images from a text prompt with FLUX.2-dev, self-hosted on dedicated GPU hardware. Returns base64-encoded PNGs. Requires a key scoped for images.
POST /api/v1/images
Request
curl https://api.webanto.com/api/v1/images \
-H "Authorization: Bearer $WEBANTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "model": "flux.2-dev", "prompt": "a red maple leaf on a white background, studio product photo", "size": "1024x1024" }'Response
{
"created": 1730000000,
"model": "flux.2-dev",
"data": [{ "b64_json": "iVBORw0KGgo..." }],
"credits": 1
}Isolates the product and returns it on a solid white background — ready for marketplace main images. Unlike the other endpoints this one is binary in, binary out — POST the raw image bytes with an image/* Content-Type and the result comes back as the response body. Credits are reported in the X-Webanto-Credits header. Returns 422 if no foreground subject is detected.
POST /api/v1/images/remove-background
Request
curl https://api.webanto.com/api/v1/images/remove-background \
-H "Authorization: Bearer $WEBANTO_API_KEY" \
-H "Content-Type: image/jpeg" \
--data-binary @product.jpg \
--output cutout.pngResponse
HTTP/1.1 200 OK
Content-Type: image/png
X-Webanto-Model: birefnet-general
X-Webanto-Credits: 2
<raw PNG bytes — product on solid white>Generate a chat completion. Requires a key scoped for chat.
POST /api/v1/chat
Request
curl https://api.webanto.com/api/v1/chat \
-H "Authorization: Bearer $WEBANTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen",
"messages": [{ "role": "user", "content": "Explain embeddings in one sentence." }]
}'Response
{
"id": "chatcmpl-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"object": "chat.completion",
"created": 1721260800,
"model": "qwen",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "..." },
"finish_reason": "stop"
}
],
"usage": { "prompt_tokens": 12, "completion_tokens": 24, "total_tokens": 36 },
"credits": 1
}Request — reasoning disabled
For extraction, classification, and structured-output work, set reasoning_effort to "none". The model skips its hidden reasoning phase, which cuts completion tokens — and therefore credits — by a large factor, and removes the risk of an empty response caused by reasoning consuming the whole max_tokens budget.
curl https://api.webanto.com/api/v1/chat \
-H "Authorization: Bearer $WEBANTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen",
"reasoning_effort": "none",
"messages": [{ "role": "user", "content": "Extract the year as a bare number: The treaty was signed in 1885." }]
}'Two lightweight checks: an unauthenticated liveness probe and an authenticated key check.
GET /api/v1/status
Liveness — no auth. Returns status and timestamp fields.
{ "status": "ok", "timestamp": "..." }GET /api/v1/health
Verifies your key and returns ok, organizationId, and scopes fields.
{ "ok": true, "organizationId": "...", "scopes": ["chat", "embeddings", "images"] }Embeddings are charged by number of inputs; chat is charged by total tokens used. Each response includes the credits charged. Requests are rate limited per API key; exceeding the limit returns 429 with a Retry-After header.
Wiring this up with an AI coding assistant? Copy the prompt below and hand it to your agent — a self-contained spec of the endpoints, auth, models, and error handling.
# Integrate with the Webanto AI API
You are integrating an app with Webanto's inference API (chat + embeddings).
It is OpenAI-shaped but NOT the OpenAI API — follow this exact contract.
## Base URL and auth
- Base URL: https://api.webanto.com/api/v1
- Get an API key at https://webanto.com/account/settings/api-keys (format: wba_live_...).
Keys are scoped per endpoint: "chat" and/or "embeddings".
- Send it as header: Authorization: Bearer wba_live_... (or x-api-key: wba_live_...).
- Server-side only. Never expose the key in a browser or client bundle.
## POST /api/v1/chat (scope: chat)
Request body:
{
"model": "qwen",
"messages": [{ "role": "system|user|assistant", "content": "..." }],
"max_tokens": 1024,
"temperature": 0.7,
"use_memory": false,
"reasoning_effort": "none"
}
- model must be "qwen" (multimodal: text + vision). messages: 1-50 turns.
- qwen is a REASONING model: keep max_tokens >= ~1024 or the visible output can be empty.
- reasoning_effort is OPTIONAL and defaults to reasoning ON.
Set "none" for extraction, classification, or structured-output work: it skips the
hidden reasoning phase, which cuts completion tokens (and therefore credits) by a
large factor and removes the empty-output risk above, since nothing is spent on
reasoning. Use the default for multi-step logic, math, and planning.
"low" | "medium" | "high" are accepted for OpenAI SDK compatibility but are NOT
differentiated — all three mean reasoning ON.
- BILLING: credits are charged on total tokens, and reasoning tokens count toward
completion_tokens even though the reasoning text is never returned. That is why
reasoning_effort "none" is the single biggest cost lever on this endpoint.
- VISION: a turn's "content" is a string OR an array of parts to send an image:
"content": [
{ "type": "text", "text": "What card is this?" },
{ "type": "image_url", "image_url": { "url": "https://cdn.example.com/card.jpg" } }
]
image_url.url accepts an https:// URL or a base64 data:image/...;base64,... URL.
Base64 must fit the ~4.5MB request-body limit — use an https URL for larger images.
Response body:
{
"id": "chatcmpl-...", "object": "chat.completion", "created": 0, "model": "qwen",
"choices": [{ "index": 0, "message": { "role": "assistant", "content": "..." }, "finish_reason": "stop" }],
"usage": { "prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0 },
"credits": 1
}
## POST /api/v1/embeddings (scope: embeddings)
Request body: { "model": "nomic-embed-text", "input": "text" | ["t1", "t2"] }
- Models: nomic-embed-text (text), clip (text + image, shared space), dinov3 (image).
- input: up to 100 items, each <= 8192 chars.
Response body:
{
"model": "nomic-embed-text",
"data": [{ "index": 0, "embedding": [0.01, -0.02] }],
"usage": { "total_tokens": 3 },
"credits": 1
}
## POST /api/v1/image-embeddings (scope: embeddings)
DINOv3 image embeddings (1280-dim, L2-normalized). Custom (non-OpenAI) contract.
Request body: one of, up to 60 images per batch (backend is CPU, ~0.3s/image):
{ "urls": ["https://cdn.example.com/card.jpg"] }
{ "images": [{ "b64": "<base64 image>" }] }
- urls must be https://. Do not mix urls and images in one request.
Response body:
{ "model": "dinov3", "dim": 1280,
"embeddings": [[0.01, -0.02, "..."]],
"errors": [], "credits": 1 }
## Health checks
- GET /api/v1/status (no auth) -> { "status": "ok", "timestamp": "..." } (liveness)
- GET /api/v1/health (auth) -> { "ok": true, "organizationId": "...", "scopes": ["chat"] }
## Errors (always check the HTTP status before parsing the body)
- 400 { "error": { "code": "invalid_request | invalid_json | unknown_model", "message": "..." } }
- 401 { "error": "Missing API key" } or { "error": "Invalid or revoked API key" }
- 403 { "error": "API key is not scoped for \"chat\"" }
- 402 { "error": { "code": "quota_exceeded", "message": "..." }, "quota": { "used": 0, "limit": 0, "remaining": 0 } }
- 429 { "error": "...", "code": "RATE_LIMIT_EXCEEDED", "retryAfter": 30 } plus a Retry-After header
- 502 { "error": { "code": "upstream_error", "message": "..." } }
## Reliability rules
- Every successful response returns "credits" (drawn from the organization AI pool). Budget for it.
- For safe retries, send an Idempotency-Key: <uuid> header on chat and embeddings.
- Requests are rate limited per API key; on 429, honor Retry-After and back off.
## Reference call (Node)
const res = await fetch("https://api.webanto.com/api/v1/chat", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.WEBANTO_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
model: "qwen",
messages: [{ role: "user", content: "Explain embeddings in one sentence." }],
}),
});
if (!res.ok) throw new Error(`Webanto API ${res.status}: ${await res.text()}`);
const { choices, credits } = await res.json();