Интеграции
Инструкции для LLM и агентов
Готовый текст, по которому агент сам найдёт модели, оценит цену, запустит задачи, дождётся результата и свяжет модели в цепочку.
Как передать агенту
#- Дайте агенту ссылку https://lumv.app/llms-full.txt — полную инструкцию с актуальным каталогом и схемами всех моделей — или вставьте текст ниже. Короткий указатель для поиска — llms.txt.
- Передайте ключ через переменную окружения
LUMV_API_KEYили хранилище секретов, а не в тексте промпта. - Укажите бюджет и число результатов: агент обязан оценить цену через estimate до запуска.
Готовая инструкция
#Инструкция на английском языке (English): так модели точнее следуют правилам. Она совпадает со статической частью llms-full.txt.
# lumv.app API guide for LLMs and automated agents
> lumv.app generates images, video, 3D models, speech, sound effects and music, and serves text chat models.
> Agents use a personal API key. Generations are asynchronous jobs (estimate, start, poll, download) at
> /v1/generations; text models use the OpenAI-compatible /v1/chat/completions and /v1/responses.
> Money is counted in credits: 1 credit = 1 RUB = 100 kopecks. Every *Cents field is an integer number of kopecks.
## Access
- Origin: https://lumv.app. API base URL, also for OpenAI SDKs: https://lumv.app/v1.
- The user signs in at https://lumv.app, funds a wallet and creates a personal key at
https://lumv.app/account/api/keys. The full key (sk-lumv-...) is shown once. A key can have an expiry date and a
monthly spending limit; a user can hold up to 20 active keys.
- Send Authorization: Bearer <LUMV_API_KEY> on every protected request, including file downloads. /v1 ignores cookies.
- Read the key from a secret store or the LUMV_API_KEY environment variable. Never write it into code, URLs,
repositories, messages or logs, and never send it to any host other than lumv.app.
- Public without a key: GET /v1/generation-models, GET /v1/generation-models/:id, /llms.txt, /llms-full.txt and the
/docs/api pages. Every other /v1 route requires the key, including GET /v1/models.
- The user sees every API request and its cost at https://lumv.app/account/api/usage.
## Endpoints
| Method | Path | Purpose |
| --- | --- | --- |
| GET | /v1/generation-models | Public list of enabled generation models: fields, scenarios, examples |
| GET | /v1/generation-models/:id | One generation model contract (404 model_not_found if disabled or unknown) |
| POST | /v1/generations/estimate | Free price quote for a request body; nothing is charged or created |
| POST | /v1/generations | Start an asynchronous generation: 202 { generation } |
| GET | /v1/generations/:id | Status and results of your own generation |
| GET, HEAD | /v1/generations/:id/assets/:asset | Download a result file (Range; ?download=1 for an attachment) |
| POST | /v1/uploads | Create an upload session for a new input file |
| PUT | /v1/uploads/:id/content | Send the file bytes with X-Upload-Token |
| POST | /v1/uploads/:id/complete | Finish the upload and start validation |
| DELETE | /v1/uploads/:id | Cancel an unfinished upload |
| GET | /v1/assets/:id | State of an owned asset |
| GET, HEAD | /v1/assets/:id/content | Content of an owned asset (Range; ?role=thumbnail for image previews) |
| GET | /v1/projects | Project folders you can store generations in (projectId) |
| GET | /v1/models, /v1/models/:id | OpenAI-compatible list of text models |
| POST | /v1/chat/completions | OpenAI Chat Completions for text models |
| POST | /v1/responses | OpenAI Responses for text models |
| GET, DELETE | /v1/responses/:id | Read or delete a stored response |
| GET | /v1/responses/:id/input_items | Input items of a stored response |
## Choosing a generation model
- Read GET /v1/generation-models (or the live catalog at the end of /llms-full.txt) before a task. Never invent model
IDs, field names or option values.
- A model has id (send it as "model"), name, description, category, endpoint ("/v1/generations"), basePriceCents
(indicative starting price), fields and scenarios. name, description and field labels are UI text and may be Russian;
always use the machine names.
- Field keys: name, label, description, type, required, defaultValue, options [{ value, label }], minimum, maximum,
step, maximumLength, accept, multiple, maximumItems, requires, visibleWhen { field, equals }, valueType, routingOnly,
advanced, scenarios.
- Generation models are called only through POST /v1/generations, never through /chat/completions, /responses or
/images/generations. Text models from GET /v1/models are called only through the OpenAI-compatible endpoints.
## Request body
```json
{
"model": "MODEL_ID_FROM_CATALOG",
"values": { "prompt": "A red fox in fresh snow, golden hour" },
"inputAssets": [{ "fieldName": "FILE_FIELD_NAME", "assetId": "READY_ASSET_ID", "position": 0 }],
"projectId": "OPTIONAL_PROJECT_ID"
}
```
- Only model, values, inputAssets and projectId are accepted at the top level; any other key returns 400.
- values contains only field names of that model; unknown names, null and wrong JSON types return 400.
- Types: text, textarea and dimensions are JSON strings (dimensions such as "1024x1024" or an option value); number is
a JSON number; boolean is true or false; select is one of options[].value as a string, or as a JSON number when
valueType is "number"; json is a JSON object or array, or a string containing JSON. Omitted fields use defaultValue.
- File fields (type "file") never go into values. Pass them in inputAssets: fieldName is the file field, assetId is an
owned asset with status "ready", position is a 0-based index (0..maximumItems-1 for multiple fields). At most 100
references per request. URLs and base64 data are rejected.
- requires: the field may be sent only together with the named field. visibleWhen: the field applies only while another
field equals the given value. required, maximumLength, minimum, maximum, step, options and maximumItems are enforced;
contract violations return 422 with code invalid_model_input.
## Scenarios
A model can have several scenarios. The server picks one from your request: scenarios are checked in the listed order
and the first matching condition wins; the scenario without a condition is the fallback. Conditions: file_present (a
file is attached to that field), truthy (the field is true, "true", "on" or a positive number), equals (the field equals
value exactly). A field with a scenarios list exists only in those scenarios, and its required flag applies only there.
Scenario limits override a field's minimum and maximum. Every scenario has a ready "example" request in the JSON contract.
## Estimate
POST /v1/generations/estimate takes the same body you will start (projectId is ignored here):
```json
{
"model": "MODEL_ID",
"costCents": 1500,
"currency": "RUB",
"charged": false,
"billing": { "wallet": "personal", "unlimited": false, "chargeCents": 1500, "keyBinding": "personal" }
}
```
- costCents is the catalog price of this exact request in kopecks (1500 = 15 credits).
- billing is the wallet that would pay: wallet "personal" or "team" (then also teamName); unlimited is true for an
unlimited team; chargeCents is what would actually be debited (0 for unlimited teams); providerEstimateUsdMicros
(unlimited teams only) is the expected provider cost in millionths of a US dollar. keyBinding is the key's wallet
mode: "personal", "team" or "account" (follows the wallet selected in the web app).
- The estimate validates values and inputAssets. It does not check the balance, reserve money, check projectId, check
provider availability or create a job. Prices can change between estimate and start.
- Before paid runs, agree on the total budget and the number of runs with the user. A successful test of one item is
not permission to run ten. Treat the key's monthly limit as a hard cap.
## Start and poll
- POST /v1/generations reserves the price from the wallet and returns HTTP 202, Retry-After: 3 and { "generation" }.
- GET /v1/generations/:id returns { "generation" }. status: uploading, queued, processing (keep polling every 3-5
seconds, back off on temporary errors), completed (results ready) or failed (read error; the reserve is returned
automatically and refunded becomes 1).
- A client timeout does not cancel the job: store generation.id and resume polling later. Do not blindly retry a
failed job; read error and check the budget first. Other users' generations return 404.
- Generation fields: id, object ("generation"), status, error, createdAt and updatedAt (Unix ms), modelId (catalog id),
modelName, category, scenarioName, parameters (display summary), prompt (main text instruction or null),
reuseValues (non-file values for repeating the request), costCents (charged kopecks, 0 for unlimited teams),
refunded, billingMode ("personal", "team" or "team_unlimited"), usageUsdMicros (provider cost in micro-USD for
team_unlimited, otherwise null), projectId, projectName, assets, inputAssets, previewUrl, viewerUrl, viewerFormat,
modelUrl, downloadUrl and textOutput.
## Results and downloads
- assets[]: id, url, downloadUrl, contentType, fileName, fileSize, mediaAssetId. url and downloadUrl are relative
(/v1/generations/:id/assets/:asset, downloadUrl adds ?download=1). Prefix https://lumv.app and send the same Bearer
header. GET, HEAD and Range requests are supported.
- previewUrl is the main preview; viewerUrl, modelUrl and downloadUrl point to the main 3D file (viewerFormat "gltf" or
"fbx"); textOutput holds text results; inputAssets[] lists the files used as inputs.
- Never hand these URLs to a model or a third party; reuse results by mediaAssetId instead.
## Chaining results
mediaAssetId is the owned library asset of a result. It can be null briefly while the result is being saved: poll the
generation until it appears, then GET /v1/assets/:mediaAssetId until asset.status is "ready", and pass it as
inputAssets[].assetId to the next model. Owned images, videos and audio can be reused when the field's accept list
allows their type. If an asset does not become ready in a reasonable time, report it and keep the generation id.
Example task "10 images -> 10 3D models":
1. Pick an image model and a 3D model with an image file field from the catalog.
2. Fix parameters and the budget of the whole chain; estimate each step before starting it.
3. Keep a manifest for the 10 pairs: prompt, idempotency keys, generation IDs, asset IDs, cost, state. Save it after
every step so the run can resume after an interruption.
4. Generate the image of a pair; wait for completed and a ready image asset.
5. Pass that assetId to the 3D model through inputAssets. For Tripo, for example, choose generation_mode h31_image or
p1_image and fieldName image_url; take the exact limits from the current schema.
6. Wait for the completed 3D model, download it and mark the pair done.
7. Continue with the other pairs. Keep at most 4 unfinished requests per key; sequential runs are simplest.
## Uploading new input files
1. POST /v1/uploads with { "profile": "reference_image", "fileName": "input.png", "contentType": "image/png",
"size": BYTES } and an Idempotency-Key header (required, 8-128 characters from A-Z a-z 0-9 . _ : -). The same key and
declaration return the same session. Response 201 (200 on replay): { "upload": { id, assetId, state, uploadUrl,
leaseToken, maximumBytes, expiresAt } }.
2. PUT https://lumv.app + uploadUrl with the raw bytes and the headers Authorization, Content-Type and
X-Upload-Token: <leaseToken>. Never send more than maximumBytes.
3. POST /v1/uploads/:id/complete returns 202 { assetId, status: "pending" }.
4. GET /v1/assets/:assetId until asset.status is "ready" ("pending" and "validating" mean wait; "rejected" means stop
and report).
- Profiles for generation inputs: reference_image (JPEG, PNG or WebP up to 10 MiB) and image_mask (PNG up to 10 MiB,
same size as the source image; for mask fields). chat_pdf and chat_text are web chat attachments; the text API
accepts text content only. Uploading your own video or audio is not supported; reuse generated results by ID.
- Upload sessions expire after 1 hour; DELETE /v1/uploads/:id cancels an unfinished one. Account quotas (by default
2 active upload sessions, 10 files awaiting validation, 250 MiB per day, 1 GiB of storage) return 429 when exceeded.
## Projects
projectId (POST /v1/generations only) stores the result in a project folder of the web workspace: your own project,
or a team-shared project where you have contribute access. A view-only project returns 403; a missing or invisible one
returns 404. GET /v1/projects lists the folders you can store results in:
{ "object": "list", "data": [{ "id", "object": "project", "name", "color", "team" (team name or null), "owned" }] }.
The id is also in the project page URL (https://lumv.app/projects/<id>). The generation then reports projectId
and projectName. projectId is part of the idempotency fingerprint. Text endpoints do not accept projectId.
## Wallets and billing
- Every API key is bound to a wallet when it is created (the user can change it later in /account/api/keys): the
personal balance, one team the user belongs to, or "account" (follow the wallet selected in the web app's account
settings or header switcher at request time; keys created before key binding use this mode). The estimate's billing
block shows which wallet will pay and keyBinding shows the key's mode.
- A key bound to a team the user has left, or to an archived team, is never silently switched to another wallet:
estimates and new requests return 403 with code wallet_unavailable until the user picks another wallet.
- Personal and prepaid team wallets: the price is reserved at start; refunds and adjustments return to the same wallet.
Insufficient funds return 402 (for a team wallet the message names the team).
- Unlimited teams: nothing is debited. costCents and billing.chargeCents are 0, billingMode is "team_unlimited", and
usageUsdMicros or providerEstimateUsdMicros report the provider cost (1 USD = 1,000,000 micros).
- A team that uses its own provider keys reaches only the models those providers serve; other models fail at start
with 503 (no suitable connection for the team). Estimates do not detect this.
- The key's monthly limit counts reserves of the current UTC calendar month (failed requests excluded); a request that
would exceed it returns 402.
- Text models are billed by tokens: the start reserves the maximum (context, max tokens and the reasoning reserve);
the final charge follows the reported usage and never exceeds the reserve.
## Idempotency and retries
- Send a unique Idempotency-Key header (1-128 printable ASCII characters, no spaces) with every logical
POST /v1/generations, /v1/chat/completions and /v1/responses request. Keys are scoped to the API key.
- The same key with the same body (including projectId) returns the original job instead of charging again; the same
key with a different body returns 409.
- Save the key and the body before sending. After a timeout or a network error, retry with the same key and body.
Never change the key while the outcome is unknown, or the request may run and be charged twice.
- Retry only 429, 503, 504 and network errors, a limited number of times with exponential backoff, and honor
Retry-After when present. Never retry in an endless loop.
## Limits
- 4 unfinished requests per key, generations and text requests combined; more return 429 until one finishes.
- JSON bodies up to 6,000,000 bytes (the gateway rejects anything over 8 MiB); larger bodies return 413.
- inputAssets: up to 100 references per request, and each field's maximumItems.
- Gateway rate limit of about 100 requests per second per IP address (429).
- Upload content: the profile maximum (10 MiB for images); the gateway accepts at most 20 MiB per PUT.
- Text requests: 1-1000 messages, up to 200,000 characters per text part, up to 32 tools, max tokens from 1 to the
model's output limit (Gemini 4 Argon: 1,000,000; default 4096). A non-streaming request waits up to 14 minutes (2 hours when max
tokens exceed 128,000) and then returns 504; repeat it with the same Idempotency-Key to get the same result.
## Errors
Errors look like { "error": { "message", "type", "param": null, "code" } }. message is human-readable and usually in
Russian, so branch on the HTTP status and code. type is "authentication_error" for 401 and "invalid_request_error"
otherwise; code is null, invalid_request_error or one of model_not_found, not_found, response_not_found, invalid_model_input,
invalid_project, wallet_unavailable, rate_limit_exceeded. The gateway can answer 413 or 429 without a JSON body.
| Status | Meaning | What to do |
| --- | --- | --- |
| 400 | Invalid JSON, unknown top-level key or field, wrong value type, file in values, bad Idempotency-Key, unsupported OpenAI parameter | Fix the request; do not retry unchanged |
| 401 | Missing, revoked or expired key | Stop and ask the user for a valid key |
| 402 | Wallet balance too low or the key's monthly limit reached | Stop and tell the user |
| 403 | The project does not accept new results from you (invalid_project), or the key's team wallet is no longer available (wallet_unavailable) | Drop projectId, or ask the user to choose another wallet for the key |
| 404 | Model, generation, asset, upload, project or stored response is missing or not yours | Check the IDs |
| 408 | Upload body was not received in time | Repeat the PUT |
| 409 | Idempotency-Key reused with a different body | Resend the original body, or use a new key for a new task |
| 413 | Body or file too large | Make it smaller |
| 415 | Unsupported upload profile or file format | Use a supported profile and type |
| 416 | Invalid Range header | Fix the range |
| 422 | values break the model contract (REQUIRED, INVALID_*, OUT_OF_RANGE, TEXT_TOO_LONG, TOO_MANY_FILES, REQUIRES_FIELD) | Fix values against the schema |
| 429 | 4 unfinished requests on the key, gateway rate limit or upload quota | Wait for running jobs, then back off |
| 502 | The text model failed to answer (the reserve is returned) | Retry later with a new Idempotency-Key |
| 503 | Temporary failure, no available provider (also: no suitable connection for the team), uploads disabled | Limited retries with the same key |
| 504 | A text request timed out while waiting | Retry with the same Idempotency-Key |
## OpenAI-compatible text API
Base URL https://lumv.app/v1, the lumv key as the API key, model IDs from GET /v1/models (or the text models at the end
of /llms-full.txt). GET /v1/models returns { "object": "list", "data": [{ "id", "object": "model", "created": 0,
"owned_by": "lumv" }] }. Text only: image, audio and file inputs, response_format and built-in tools are not supported.
### POST /v1/chat/completions
- Accepted: model, messages (roles system, developer, user, assistant, tool; content is a string or an array of
{ "type": "text", "text" } parts), max_tokens or max_completion_tokens, temperature (0-2), top_p (above 0, up to 1),
tools, tool_choice ("none", "auto", "required" or { "type": "function", "function": { "name" } }),
parallel_tool_calls, reasoning_effort, stream, stream_options.include_usage and n (1 only). response_format, audio
and modalities return 400; other OpenAI parameters are ignored.
- Response: chat.completion with choices[0].message (content and/or tool_calls), finish_reason ("stop", "length" or
"tool_calls") and usage (prompt_tokens, completion_tokens, total_tokens, prompt_tokens_details.cached_tokens).
- stream: true returns text/event-stream with chat.completion.chunk objects, ": keep-alive" comments every 10 seconds,
tool_calls in one chunk at the end, a final usage chunk with empty choices when include_usage is true, errors as
data: { "error" } and the terminator data: [DONE].
### POST /v1/responses
- Accepted keys: model, input (a string, or items: messages with roles system, developer, user or assistant and string
or input_text/output_text content; function_call; function_call_output; reasoning), instructions,
previous_response_id, max_output_tokens, stream, store (default true), tools, tool_choice, temperature, top_p,
parallel_tool_calls, reasoning, text ({ "format": { "type": "text" } } and verbosity low, medium or high), metadata
(up to 16 string pairs; keys up to 64 and values up to 512 characters), background (false only), truncation
("disabled" only), stream_options ({ "include_obfuscation": false } only), prompt_cache_key and include
(["reasoning.encrypted_content"] only). Any other key returns 400.
- Response: object "response" with status ("completed", "failed" or "in_progress"), output items (message with
output_text, function_call with call_id, name and arguments, reasoning with summary_text) and usage (input_tokens,
output_tokens, input_tokens_details.cached_tokens, output_tokens_details.reasoning_tokens).
- Stored responses (store true): GET /v1/responses/:id, GET /v1/responses/:id/input_items (a list, has_more false) and
DELETE /v1/responses/:id ({ "id", "object": "response.deleted", "deleted": true }). previous_response_id continues a
completed stored response; earlier system and developer messages are not carried over, so send instructions again.
- stream: true emits events with type and sequence_number: response.created, response.in_progress,
response.output_item.added, response.content_part.added, response.output_text.delta, response.output_text.done,
response.content_part.done, response.output_item.done, response.function_call_arguments.delta,
response.function_call_arguments.done, response.completed, response.failed and error.
### Function tools
Declare up to 32 tools of type "function" (name matching [a-zA-Z0-9_-]{1,64}, optional description, JSON Schema
parameters and strict). Chat Completions nests them as { "type": "function", "function": { ... } }; Responses uses the
flat { "type": "function", "name", ... } form. When the model calls a tool, run it yourself: send back the assistant
message with tool_calls and then { "role": "tool", "tool_call_id", "content" } messages, or function_call_output items
with call_id in Responses. lumv never executes your tools.
### Reasoning effort
reasoning_effort (Chat Completions) or reasoning.effort (Responses) accepts none, minimal, low, medium, high, xhigh, max
or ultra, but only the values a model lists (reasoning_effort in the text model catalog); other values return 400.
Higher effort increases the reserved price. Responses also accept reasoning.summary ("auto", "concise" or "detailed";
the alias generate_summary must match it); summaries appear as reasoning output items only when the provider returns
them. DeepSeek models combined with function tools accept only effort none or no effort.