Build on VERIS.
One endpoint per AI capability. Multi-provider routing, cost controls, and full request history are included. Everything below is live today.
Base URL
https://veris.digital/api/v1
Health, the OpenAPI spec, and CORS preflight need no authentication. Every other endpoint requires a bearer token.
Authentication
Authorization: Bearer $VERIS_API_KEY
Keys look like veris_ab12cd_…. Legacy aios_ keys still work. There is no x-api-key header. Create a key inside VERIS at Applications → your application → Developer → API keys. A key is scoped to its workspace and can address any application and environment in it.
Health check
curl https://veris.digital/api/v1/health
{"status":"ok","version":"1.0.0","capabilities":["chat","embed"],"timestamp":"2026-08-02T12:00:00.000Z"}Chat
curl -X POST https://veris.digital/api/v1/chat \
-H "Authorization: Bearer $VERIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"application": "resume-parser",
"environment": "production",
"workload": "extract",
"input": "Extract name, email, and years of experience from this resume."
}'| Field | Required | Description |
|---|---|---|
| application | Yes | Application slug. project is accepted as a legacy alias, and OpenAI SDK clients may send it as model. |
| environment | No | Defaults to production. |
| workload | No | Workload tag used for routing, evaluation, and cost attribution. |
| input | Either | Shorthand for a single user message. |
| messages | Either | Array of { role, content }. One of input or messages is required. |
| maxCostUsd | No | Reject the request if the cheapest candidate exceeds this cost. |
{
"requestId": "8f1c0b2e-…",
"status": "ok",
"provider": "openai",
"model": "gpt-4o-mini",
"text": "{\"name\":\"Ada Lovelace\",…}",
"inputTokens": 42,
"outputTokens": 128,
"latencyMs": 812,
"costUsd": 0.00034,
"fallbackUsed": false,
"workload": "extract"
}Every response carries an x-veris-request-id header matching requestId. Use it to find the routing decision in Request History. For streaming, use the OpenAI-compatible endpoint below with stream: true.
OpenAI-compatible chat
POST /api/v1/chat/completions speaks the OpenAI chat completions contract. Standard fields keep standard meanings: model is a model, never an application. Send veris-auto to let VERIS choose the model for the workload. The application comes from your API key, or from the x-veris-application header.
Sending your application name as the model, for example "model": "amatch", is rejected rather than silently ignored. Send "model": "veris-auto" and pass the application in the x-veris-application header. To constrain which models VERIS may choose, set model preferences on the workload.
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://veris.digital/api/v1",
apiKey: process.env.VERIS_API_KEY,
});
const res = await client.chat.completions.create({
model: "veris-auto", // VERIS selects the model
messages: [
{ role: "system", content: "You are a resume parser. Reply with JSON." },
{ role: "user", content: "Extract name, email, and years of experience." },
],
});
console.log(res.choices[0].message.content);Routing context travels in headers, so the request body stays a standard OpenAI body: x-veris-application, x-veris-environment, x-veris-workload, x-veris-strategy, x-veris-domain.
const stream = await client.chat.completions.create(
{
model: "veris-auto",
messages: [{ role: "user", content: "Summarise this contract." }],
stream: true,
},
{ headers: { "x-veris-application": "contract-analyzer", "x-veris-workload": "summarise" } },
);
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}Tool turns round-trip. Send the assistant message with its tool_calls, then the tool message carrying the matching tool_call_id. VERIS transports tool history and preserves call ids end to end. It never executes a tool, and it only routes the turn to a model that supports tools.
VERIS never silently ignores a parameter. A field it cannot honour returns a 400 naming the field, so you always know what ran. A tool result whose tool_call_id matches no preceding call is rejected by name rather than dropped. Responses carry x-veris-request-id, x-veris-provider and x-veris-model.
Embeddings
curl -X POST https://veris.digital/api/v1/embeddings \
-H "Authorization: Bearer $VERIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"application": "resume-parser",
"environment": "production",
"input": "Senior software engineer with 8 years of backend experience."
}'input is a string or an array of strings. The response follows the OpenAI shape and adds requestId, provider, dimensions, latencyMs, costUsd, and fallbackUsed, all safe to ignore.
Document OCR
curl -X POST https://veris.digital/api/v1/document/ocr \
-H "Authorization: Bearer $VERIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"application": "resume-parser",
"environment": "production",
"document": {
"source": "url",
"mime_type": "application/pdf",
"url": "https://example.com/invoice.pdf"
}
}'Send the file as a permitted HTTPS url, as inline base64 ("source": "inline"), or as a multipart upload. The response returns page text plus page_count, pages_succeeded, pages_failed, and the provider's own charge in its own currency. When a provider prices in a currency other than USD, cost_usd is null rather than a misleading zero.
Errors
{
"error": {
"code": "invalid_api_key",
"message": "The API key is invalid.",
"requestId": "8f1c0b2e-…"
}
}| Code | HTTP | When |
|---|---|---|
| missing_api_key | 401 | No Authorization: Bearer header. |
| invalid_api_key | 401 | Malformed, revoked, expired, or unknown key. |
| invalid_request | 400 | Request body failed validation. |
| project_not_found | 404 | Application slug does not exist in this workspace. |
| environment_not_found | 404 | Environment does not exist for this application. |
| budget_blocked | 402 | Monthly budget cap reached. |
| no_candidates | 422 | No provider satisfies the routing policy. |
| rate_limited | 429 | Too many requests. Back off with jitter. |
| internal | 500 | Every upstream provider failed after fallbacks. |
Rate limits
| Plan | Requests | Concurrent |
|---|---|---|
| Free | 60 / minute | 5 |
| Team | 600 / minute | 50 |
| Business | 3,000 / minute | 250 |
| Enterprise | Custom | Custom |
Limits apply per workspace. Exceeding one returns 429 with code rate_limited.
Versioning
/api/v1 is stable. Breaking changes ship in /v2. New optional fields and new capabilities may appear in v1 at any time.