Models
List the models you can reach through Recovea, and retrieve a single one by id. Both endpoints return the exact OpenAI shapes, so your existing model-picker and SDK code work unchanged.
The list is per-tenant: it is derived from the provider keys you've connected in the dashboard, so the ids you get back are exactly the ids you can actually invoke. Today it merges your OpenAI, Anthropic, and OpenRouter keys, each model tagged by its owned_by provider. OpenRouter entries are vendor/model slug ids passed through verbatim — exactly the form you pass as model on /v1. (Native surfaces for more providers — Google first — are planned.)
List models
GET /v1/models
Returns an un-paginated list of every model reachable on your connected provider keys.
curl https://api.recovea.ai/v1/models \
-H "Authorization: Bearer $RECOVEA_API_KEY"
from openai import OpenAI
client = OpenAI(
base_url="https://api.recovea.ai/v1",
api_key="rcv_live_…",
)
models = client.models.list()
for m in models.data:
print(m.id, m.owned_by)
Response
{
"object": "list",
"data": [
{ "id": "google/gemini-2.5-pro", "object": "model", "created": 1750000000, "owned_by": "openrouter" },
{ "id": "claude-opus-4-8", "object": "model", "created": 1730332800, "owned_by": "anthropic" },
{ "id": "gpt-4o-2024-08-06", "object": "model", "created": 1722902400, "owned_by": "system" },
{ "id": "gpt-4o", "object": "model", "created": 1715367049, "owned_by": "openai" },
{ "id": "text-embedding-3-small", "object": "model", "created": 1705948997, "owned_by": "openai" }
]
}
This endpoint is not paginated: it returns the full accessible set in a single response, with no first_id / last_id / has_more. That matches OpenAI, so the SDK's auto-pagination iterator is a no-op here.
The model object
Each entry has exactly four fields:
| Field | Type | Description |
|---|---|---|
id | string | The model id you pass as model in requests (e.g. gpt-4o, or a vendor/model slug like google/gemini-2.5-pro; claude-… ids are invoked on the /anthropic surface). |
object | string | Always the literal "model". |
created | integer | Creation time, Unix seconds. |
owned_by | string | Owner, e.g. "openai", "anthropic", "openrouter", "system", or an org-… id for fine-tunes. |
Recovea does not add legacy permission / root / parent fields, and adds no extra fields of its own. Model capabilities (context window, modalities, cutoff) are intentionally not part of this object, the same as OpenAI.
Retrieve a model
GET /v1/models/{model}
Returns the bare model object: same four fields, no list envelope.
curl https://api.recovea.ai/v1/models/gpt-4o \
-H "Authorization: Bearer $RECOVEA_API_KEY"
model = client.models.retrieve("gpt-4o")
print(model.id, model.created, model.owned_by)
{
"id": "gpt-4o",
"object": "model",
"created": 1715367049,
"owned_by": "openai"
}
A model id that isn't on your connected keys returns HTTP 404 with the standard error envelope:
{
"error": {
"message": "The model `gpt-4o-pro` does not exist or you do not have access to it.",
"type": "invalid_request_error",
"param": null,
"code": "model_not_found"
}
}
A bare non-OpenAI id sent to the /v1 inference endpoints gets the same model_not_found envelope with a message that names the invocable form — /v1 serves the long tail only under OpenRouter's vendor/model ids:
{
"error": {
"message": "The model `claude-opus-4-8` does not exist or you do not have access to it. This surface serves it via OpenRouter under its vendor/model id — use `anthropic/claude-opus-4-8` (GET /v1/models lists the invocable ids). Anthropic models are also served natively on the /anthropic surface.",
"type": "invalid_request_error",
"param": null,
"code": "model_not_found"
}
}
Every retrievable id is also present in the list response for the same key. (vendor/model slug ids contain a /, so they appear in the list and are invoked directly; the single-id retrieve path serves bare ids.)
How the list is derived
Recovea computes your model list from the upstream provider key(s) you've connected, pass-through:
- It proxies and caches each connected provider's own
/v1/models, then merges and de-duplicates across your keys. - Ids are passed through unchanged: both floating aliases (
gpt-4o) and their dated snapshots (gpt-4o-2024-08-06) appear as distinct entries, so snapshot-pinned requests stay byte-for-byte the same. - The cache has a short TTL and refreshes when you add or rotate a key.
- If a connected key is healthy on one provider but invalid on another, you get the healthy provider's models back. Only when every connected key is rejected do you get the provider's own 401 mirrored back verbatim, the truest drop-in behavior.
Model-discovery responses carry the six x-ratelimit-* headers (your current limits). The x-request-id / x-recovea-trace-id correlation headers are added on the inference endpoints (chat/completions, embeddings, and the /anthropic surface), not on model lookups.
Next
- Chat Completions: send a request with one of these model ids
- Authentication: connecting your provider keys
- Errors: status codes and the error envelope