InfraOptimal / API
Deploy a model. Use it. Stop when you're done.
New here? The quickstart goes from launch to a first request, with copy-paste examples for OpenAI clients, coding agents and frameworks.
The API and MCP launch dedicated endpoints on InfraOptimal GPUs. Choose a prepared recipe, a supported Hugging Face checkpoint, or your own serving container. One lifecycle handles quoting, launch, connection details and Stop.
Dedicated-service data handling explains gateway and Z.ai startup processing, operational retention and credentials.
For REST, create one full-access platform key (vbc_…) in API keys to manage deployments. No MCP or cloud account connection is required. For MCP, sign in once instead; no platform key is needed. Your app uses the returned endpoint key, never the platform key.
- Application: create a dedicated key once, then Start → inference → Stop using the same URL and key each time.
- One job: quote → create → connect → inference → Stop. Each new deployment has its own URL and endpoint key. Existing deployments and keys keep working.
Choose what to run
Prepared recipe: select an offering from GET /console/api/optimized and quote its ID. It specifies the model, runtime and hardware. The GLM example below includes inference during GPU startup.
Hugging Face checkpoint: quote its repository ID or URL. The planner checks model support and access, then recommends available hardware for the requested workload. With no hardware named, the quote selects hardware by cost for the workload's stated performance targets, using measurements where available and estimates otherwise. You can name hardware explicitly. A quote checks compatibility; it does not promise a particular throughput or instantaneous startup.
POST https://infraoptimal.com/console/api/deployments/plan
Authorization: Bearer $INFEROPTIMAL_API_KEY
Content-Type: application/json
{
"model": "Qwen/Qwen3-Coder-30B-A3B-Instruct",
"workload": "agents",
"target_concurrency": 32,
"max_runtime_hours": 2
}
Read the returned hardware, price, automation and blockers. Choose an automatic launch, then pass plan_id to the helper as planId, or use the HTTP steps below. Operator-assisted quotes require coordination through the console; the helper will not silently select one. For private or gated checkpoints, supply hf_token in both the quote and raw HTTP create request. Adapter-only repos and unfamiliar architectures may need a prepared runtime instead of the standard model engine.
Bring a serving container
Quote container with image, port and health_path, plus explicit hardware. The image must start an HTTP server; its own request and response formats remain unchanged. Supported VM hardware and a paid balance are required. There is no automatic sizing or code optimization for an arbitrary image.
{
"container": {
"image": "your-registry/your-serving-image:version",
"port": 8000,
"health_path": "/health"
},
"hardware": "H100",
"max_runtime_hours": 2
}
Use raw HTTP create for private registry credentials. The connection returns the container's HTTPS address; do not assume it implements Chat Completions.
REST, MCP, the CLI and the console launch through the same plan: POST /console/api/deployments/plan, then POST /console/api/deployments with its plan_id. The default is InfraOptimal cloud, billed from your balance. To launch on a cloud you connected on the Endpoints page, add "provider" to the plan: aws, gcp, azure, lambda or modal; that cloud bills you. Over MCP the same launch is query action quote_own_cloud, then launch action launch_own_cloud. Model discovery is broader than runtime support: the quote returns requirements or blockers before launch.
One dedicated key for your application
Each optimized endpoint can have one dedicated key (vbs_…). Embed it in your application: the same key starts the endpoint, runs inference and stops it, and the URL and key stay the same every time. For example, your application calls Start when a user signs in, sends requests while they work and calls Stop when they are done. The dedicated key cannot change limits, price or keys, delete the endpoint or launch anything else. Dedicated keys are for optimized endpoints; for a custom model, contact us.
1. Get the key once
Create it from an optimized endpoint on the Endpoints page, or with your platform key. GET /console/api/services returns capabilities.canCreate. Choose startup behavior before quoting: for private_only quote rapid_coldboot: false; for qualified_bridge quote rapid_coldboot: true and approve the returned startup provider and capabilities.
POST /console/api/deployments/plan
Authorization: Bearer $INFEROPTIMAL_API_KEY
Content-Type: application/json
{
"managed_endpoint": "OFFERING_FROM_CATALOG",
"rapid_coldboot": false,
"max_runtime_hours": 2,
"max_spend_usd": 21.60
}
Review the price, startup behavior and blockers, then create the dedicated key with that plan and the same selector. Startup and spending options belong in policy, not selector.
POST /console/api/services
Authorization: Bearer $INFEROPTIMAL_API_KEY
Content-Type: application/json
{
"name": "My application",
"plan_id": "plan_FROM_QUOTE",
"selector": {"managed_endpoint": "OFFERING_FROM_CATALOG"},
"idempotency_key": "persisted-service-creation-id",
"policy": {
"startup": "private_only",
"maxHourlyUsd": 10.80,
"maxSpendUsd": 21.60,
"totalBudgetUsd": 100,
"maxRuntimeHours": 2,
"maxConcurrentRequests": 4,
"idleSeconds": null
}
}
Use your quoted selector and price; these example amounts are not an offer. The example chooses four simultaneous requests, not a platform default. Prefer the quote’s measured usage.concurrency.agents unless you need fewer, within runtime.execution.maxConcurrentRequests or usage.concurrency.at_most. An engine limit alone is not a measured speed guarantee. Save the returned service_url, base_url, model and api_key in your application's secrets. The key is returned at creation and on identical creation retries for ten minutes; it is not included in listing or inspection. Creation starts no hardware. An endpoint is never stopped for idling by default: omit idleSeconds or send null, and its owner gets one warning email after 30 idle minutes. To opt in to stopping on idle, set a whole number of seconds from 120. Idle time is billed at the endpoint’s rate, and active requests reset the idle clock.
2. Start
Read the endpoint's state with its dedicated key, then start it with the generation and admission.epoch you read.
curl "https://infraoptimal.com/services/svc_YOUR_ENDPOINT" \
-H "Authorization: Bearer $INFEROPTIMAL_DEDICATED_KEY" \
--fail-with-body --output service-status.json
It returns state (stopped, starting, ready, stopping or attention_required), generation, admission.epoch, accepts_requests, idle_seconds, idle (its summary says how long it has been idle and its price, in the offering’s unit, or null while serving or stopped) and the URLs. readiness.inference_ready means it can answer; readiness.private_ready means a private replica is ready. readiness.inference_backend identifies private, startup_bridge, mixed, unknown or null when not ready. Connection and agent setup responses include the same summary.
Prepare a Start body once from that saved status (Node 20+). If the request loses its response, resend the saved file; do not regenerate it.
node --input-type=module <<'JS'
import { readFile, writeFile } from 'node:fs/promises';
const status = JSON.parse(await readFile('service-status.json', 'utf8'));
const intent = {
idempotency_key: crypto.randomUUID(),
expected_generation: status.generation,
expected_epoch: status.admission.epoch,
expires_at: Date.now() + 5 * 60 * 1000
};
await writeFile('service-start.json', JSON.stringify(intent), { mode: 0o600 });
JS
curl -X POST "https://infraoptimal.com/services/svc_YOUR_ENDPOINT/start" \
-H "Authorization: Bearer $INFEROPTIMAL_DEDICATED_KEY" \
-H "Content-Type: application/json" \
--data-binary @service-start.json
expires_at is Unix milliseconds, at most five minutes ahead. Save the whole body before sending and retry it unchanged after a lost response. Start is idempotent and deduplicated: a retried body and simultaneous Starts share one allocation. A Start prepared before a Stop returns 409 service_start_stale; read the state again. Right after a Stop, Start can return 409 service_cleanup_pending with Retry-After while the previous hardware is released. Start keeps the endpoint's hourly ceiling, per-start cap, total authorization, daily start limit and your balance hold, and returns 402 or 429 when one is reached. When state is attention_required, Start with the key returns the reason; fix it, then press Start in the console. Private prewarm is complete when an unstopped replica has phase: "ready" and inference_backend: "private"; state: "ready" alone can mean startup-bridge availability.
3. Send requests
curl "https://infraoptimal.com/services/svc_YOUR_ENDPOINT/v1/chat/completions" \
-H "Authorization: Bearer $INFEROPTIMAL_DEDICATED_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"svc_YOUR_ENDPOINT","messages":[{"role":"user","content":"Hello"}]}'
Configure your client with base_url, the endpoint ID as model, and an advertised API mode. Anthropic clients such as Claude Code can also call /messages on a chat endpoint: set ANTHROPIC_BASE_URL to the endpoint URL without /v1 (https://infraoptimal.com/services/svc_YOUR_ENDPOINT) and ANTHROPIC_AUTH_TOKEN to the dedicated key. Those requests run as Chat Completions, with the same Start, limits and billing.
Supported api_modes identify openai_chat_completions → /chat/completions, openai_responses → /responses, or /embeddings for synchronous embedding calls. For native Responses during startup, also require the quote’s preparation.startup_capabilities.api_modes to include openai_responses; otherwise wait for private readiness. This release uses one private replica; embedding services admit one active request, which may contain a batch. Asynchronous media jobs, private repository credentials and custom containers use the explicit deployment API.
Keep the inference HTTP connection open: validated requests wait in order for startup or an available concurrency slot. Waiting and inference share policy.requestTimeoutSeconds (default 1800, maximum 3600); X-InferOptimal-Request-Timeout-Ms can set a shorter total deadline. There are 256 waiting places by default, increasing to four times the concurrency limit with a ceiling of 1024. A full waiting queue returns 429 service_queue_full with Retry-After: 5; expiration before dispatch returns 504 service_request_timeout. Eligible private services stream uploads through the gateway and validate near inference, with a current 32 MiB body limit. Startup bridges and older runtimes use the buffered 8 MiB path; concurrent input validation may wait or return 429 service_payload_capacity. Admission order begins after validation or streaming admission; the oldest requests can fill available slots in parallel. The queue stores metadata only: a disconnected HTTP request is not a saved job. Your client or network may have an earlier timeout. No inference is automatically repeated after execution may have begun. A non-streaming Chat Completions or Responses call is not cut off at a proxy timeout: the gateway answers 200 at once, sends spaces while the model works, then the usual JSON answer (leading whitespace is valid JSON, and the OpenAI SDKs read it). If the model does not start answering within 120 seconds the request returns 504 upstream_timeout with no Retry-After, because it may already have run. On a managed session (/optimized/v1) a non-streaming response must still finish within about 100 seconds; send long generations there with stream: true. Whether an endpoint does this is its connection's non_streaming_carried; where it is false, a non-streaming answer is still cut after about 100 seconds, so use stream: true for long generations. If an approved startup provider explicitly refuses a request before execution, the same connection can keep waiting for its private GPU within the original deadline.
A dedicated key does not skip the cold start. Choose qualified_bridge at creation only after approving a quote that offers startup inference and its provider/data handling; no fallback model is selected silently. The serviceChat helper in inferoptimal.mjs also understands explicit retry-safe 503 service_starting responses, without retrying ambiguous inference failures.
4. Stop
curl -X POST "https://infraoptimal.com/services/svc_YOUR_ENDPOINT/stop" \
-H "Authorization: Bearer $INFEROPTIMAL_DEDICATED_KEY"
Stop cancels waiting requests, lets active ones finish, then releases the hardware and ends billing. The URL and key stay the same, and requests return 410 until the next Start. An endpoint is never stopped for idling unless you set idleSeconds: after 30 idle minutes its owner gets one warning email with what it costs and a Stop link, and using it again re-arms the warning. Stopping an endpoint that is already stopped changes nothing.
Manage dedicated keys from your account
After Start, GET /services/{id}/wait-ready?target=private with the dedicated key waits up to 25 seconds for private inference. The platform-key route is GET /console/api/services/{id}/wait-ready; MCP is query action wait_ready. These are read-only bounded long-polls: they never start hardware. target=inference may finish on the approved startup API; target=released waits for no recorded allocations after Stop. Private readiness does not turn off separately authorized overflow.
Optional timeout_ms is 0–25000. On outcome: waiting, repeat within your job deadline with returned generation as expected_generation and admission.epoch as expected_epoch. A changed generation/epoch, failed or not_running requires inspection; do not silently restart or rent replacement hardware. Authorization is checked on each read, and a disconnected wait is not a saved job.
With your platform key: GET /console/api/services lists them and GET /console/api/services/{id} inspects one, including billing and limits. POST /console/api/services/{id}/start takes the same body as the key's Start and also clears an attention_required fault after you fix its cause. POST /console/api/services/{id}/stop with {} stops it. DELETE /console/api/services/{id} removes the endpoint and its key; active requests finish and the hardware is released. POST /console/api/services/{id}/rotate-key returns a replacement key and revokes the previous one; do not retry it automatically after a lost response. POST /console/api/services/{id}/budget with {"totalBudgetUsd": 200} changes the total authorization. The earlier /sleep and /disable routes are aliases of /stop, and /enable lets requests start it again without starting hardware.
Deployment lists mark private service allocations with service_id. Their /connection returns the parent’s stable service URL and model; reuse its saved dedicated key. Child key issuance and rotation are refused with service_managed_key and a link to the parent. Use the dedicated-key endpoint’s Start, Stop, Delete and key replacement actions.
Retry a lost creation response with the same body and idempotency key. A failed create may include service_id for inspection; never assume a transport error proves nothing was created. Reusing the idempotency key of a deleted endpoint returns 409 service_deleted. MCP uses query action list_dedicated_endpoints, change action create_dedicated_endpoint, launch action start_dedicated_endpoint and stop action stop_dedicated_endpoint, with sign-in instead of a platform key.
Node.js example: private GLM endpoint
Launch a private GLM endpoint, use its OpenAI-compatible API, and stop it when your job finishes. By default the helper waits for your private, cached replica. Set rapidColdboot: true to have Z.ai serve requests while the private GPUs load; requests then move to your replica on the same URL and key. API-provider precision and tool support can differ during startup.
Pricing: the quote gives the rate, in the offering’s unit, and the credit hold before launch. Each prepared GLM offering’s price is on its card in the console and in its quote. Existing deployments keep their accepted rate. Both are billed by the minute while active, including startup inference and idle time. Stop ends customer billing and releases the private hardware; provider cleanup may finish asynchronously.
Requires Node 20+ and the OpenAI SDK. The helper launches the endpoint and retrieves its connection and endpoint key. Your application does not need a readiness loop. Requiring immediate startup fails before rental if startup capacity is unavailable.
Download the helper and its shared policy module, keeping this directory layout:
mkdir -p inferoptimal-client/clients inferoptimal-client/console
curl -fsSL https://infraoptimal.com/clients/inferoptimal.mjs -o inferoptimal-client/clients/inferoptimal.mjs
curl -fsSL https://infraoptimal.com/console/service-policy.js -o inferoptimal-client/console/service-policy.js
import OpenAI from 'openai';
import { provisionAndWait } from './inferoptimal-client/clients/inferoptimal.mjs';
const endpoint = await provisionAndWait({
apiKey: process.env.INFEROPTIMAL_API_KEY,
model: 'glm-5.3-flash-nvfp4-cached-tp2',
idempotencyKey: crypto.randomUUID(), // save this for retries of this job
maxRuntimeHours: 12,
usagePlan: { agent_tool: 'none', agents: 1,
calls: 'My application sends Chat Completions with the quoted settings.' },
});
const client = new OpenAI({ baseURL: endpoint.baseURL, apiKey: endpoint.apiKey });
try {
const response = await client.chat.completions.create({
model: endpoint.model,
messages: [{ role: 'user', content: 'Hello' }],
});
// Run the rest of your job using the same client.
} finally {
await endpoint.stop(); // confirms Stop admission; hardware cleanup continues separately
}
Retries, idle time and cleanup
stop() returns when Stop is accepted, with the API's current billing and cleanup state. To wait for hardware release, use await endpoint.stop({ waitForCleanup: true, timeoutMs: 240000 }). The optional wait defaults to four minutes and accepts a limit of one second to fifteen minutes. If cleanup is not confirmed within that limit, cleanup_unconfirmed includes accepted: true and the last deployment state. Stop remains accepted; retry it using the same endpoint or inspect the deployment. API denials and unknown Stop outcomes still fail.
Use a new idempotency key for every new session. Reuse the saved key only to retry the same creation request. Reusing an old job's key returns its original deployment, even if it has already stopped.
maxSpendUsd is an optional spending ceiling, not a different pricing plan or an extra charge. maxRuntimeHours limits the session's duration. idleStopMinutes is off by default: an idle session is never stopped for you, and after 30 idle minutes you get one warning email with what it costs and a Stop link. Omit it or send null; set 2 or more minutes only if you want it to stop on idle. Every launch takes the same option: idle_stop_minutes on a deployment plan, idleStopMinutes on a console or AWS launch, and --idle-stop-minutes in the CLI. Setup time and tool/browser pauses do not end a job unless you explicitly select this timer. Runtime, spending and balance limits still apply. Stop the session explicitly when finished.
Keep one endpoint for the job and share its client across your browser workers. Creating one deployment per browser creates multiple hourly bills. Use the returned model name; a Hugging Face repository ID is not interchangeable with it.
During API startup, function tools need a description and tool_choice: "auto" (or omit it). Required, named, disabled or custom tool selection returns 503 startup_capability_unavailable; the request is not rewritten. Wait for dedicated_replica.state: "ready" for private-only tool semantics. The quote and connection expose startup_capabilities.
For native Responses during startup, check that startup_capabilities.api_modes includes openai_responses. A Chat-compatible bridge does not establish native Responses support. The private GPU may support Responses once ready; a successful Chat request does not verify reasoning replay or other Responses features.
Raw HTTP API
Management base URL: https://infraoptimal.com/console/api/deployments. Every request below uses Authorization: Bearer $INFEROPTIMAL_API_KEY. POST requests also use Content-Type: application/json.
1. Quote a private endpoint
POST /plan — free; starts no session or hardware.
{
"model": "glm-5.3-flash-nvfp4-cached-tp2",
"rapid_coldboot": true,
"max_runtime_hours": 12
}
The response includes plan_id, the rate in the offering’s unit (per minute or per hour), required credit hold and session limits. For an immediate-start private deployment, preparation.immediate_inference: true and dedicated_in_background: true describe the handoff. A quote alone does not allocate hardware. Resolve returned blockers before creating a session.
2. Launch
POST / — creates the deployment. The hourly-rate meter starts when inference becomes available; immediate-start inference can be available before the private GPUs finish loading.
{
"plan_id": "plan_FROM_QUOTE",
"idempotency_key": "unique-persisted-job-id",
"usage_plan": {
"agent_tool": "none",
"agents": 1,
"calls": "Our service sends chat completions with the quoted request settings."
}
}
If your own program calls the endpoint, send usage_plan exactly as above, with agent_tool set to none and calls saying how it calls the model. A launch needs a working way to run agents on the endpoint. usage_plan says how you will use it: an agent tool id from the tool list, or none with how your program calls it. A tool other than none also needs usage_plan.setup: what node ~/.inferoptimal/agents.mjs version printed, or {"by": "user", "plan": "..."}. An account that already recorded its way in the console may leave usage_plan out. Without one the launch is held with 409 agent_setup_required, which names what to set up; nothing is ordered. In the JavaScript helper, pass usagePlan.
The launch and GET /{deployment_id} carry box_agents: optimized_agents, how many concurrent agents the endpoint's box is optimized for (null where none is measured), and use_all, one line saying to keep them all busy. ?detail=true adds agent_setup, the way to run agents the launch used; the connection carries the same line in usage.concurrency. By default keep all of them busy, through parallel launches or one larger campaign, unless you choose fewer.
Save deployment_id. An immediate-start deployment returns inference_ready: true when startup inference is available; the private GPU may still be loading. GET /{deployment_id} reads its state; GET / lists your deployments.
3. Retrieve the connection and endpoint key
POST /{deployment_id}/connection with {} returns base_url, model and supported API modes.
POST /{deployment_id}/key returns the session's api_key:
{"idempotency_key":"unique-persisted-key-request-id"}
Retrying the same key request works for ten minutes. Store the endpoint key securely; do not put your platform key into the inference client.
4. Call the model
Send POST {base_url}/chat/completions using Authorization: Bearer $INFEROPTIMAL_ENDPOINT_KEY:
{
"model": "glm-5.3-flash-nvfp4",
"messages": [{"role":"user","content":"Hello"}],
"stream": true
}
The private GLM offering supports screenshot inputs, streaming, function tools and native /responses, alongside Chat Completions, with a 1,048,576-token context. For Responses, send the conversation and tool results in input with store:false; saved response IDs and background jobs are not supported. Startup support is separate: check startup_capabilities.api_modes for the requested protocol while private hardware starts. This does not add Responses support to other model offerings. Eligible private streaming routes accept bodies up to 32 MiB, including inline images; startup bridges and older runtimes use the 8 MiB buffered path.
Screenshots can be inline data URLs or public PNG, JPEG, WebP or GIF URLs. Remote images are downloaded through an isolated public service before inference: up to 6 MiB each and 64 unique URLs per request. Downloads have bounded timeouts; the expanded inline request must fit the selected transport’s body limit. Private URLs and remote audio/video URLs are not supported. Inline screenshot histories have no additional image-count limit.
5. Stop
POST /{deployment_id}/stop with {} revokes access and ends billing once accepted. A 202 response with status: "terminating" means hardware cleanup continues in the background. Read cost.metering_stopped and cleanup.provider_confirmed for their separate states; Stop admission does not claim provider cleanup has finished. Retry Stop with the same deployment ID if cleanup is still pending, or read GET /{deployment_id}. Shared startup capacity is not stopped.
Choose the service for your job
- Private 2× B200:
glm-5.3-flash-nvfp4-cached-tp2starts a private replica at the quoted price. Share one endpoint across the job’s browser workers, then Stop it when the job finishes. - Private 4× B200:
glm-5.3-flash-nvfp4-cachedselects the prepared four-GPU profile. Userapid_coldboot: trueto require startup inference, orfalseto wait for private hardware. The quote identifies the startup backend; API-provider precision may differ from the NVIDIA checkpoint. In-flight requests finish on the backend that accepted them. - Earlier Swarm name: new quotes using
glm-5.3-flash-swarmselect the same private offering. Already-created pooled sessions retain their original lifecycle: Stop ends their bill and access while the shared server stays running.
Discover offerings with GET /console/api/optimized or the catalog. Chat Completions, screenshots, tools and streaming work without an agent framework. OpenEvolve is optional research tooling, not a requirement for inference.
The helper retries transient management errors against the same deployment and preserves key-request idempotency. It does not replay model generations. If an inference stream has already returned output, do not blindly retry it as a new generation.
Errors return error and code: 401 invalid key; 403 insufficient access; 402 funding required; 409 state or idempotency conflict; 413 request too large; 429 rate limit; 503 inference unavailable. Preserve the response and deployment ID when reporting a failure.
Whisper: speech to text
Quote a Whisper checkpoint the engine serves natively (architecture WhisperForConditionalGeneration, for example model: "openai/whisper-large-v3-turbo") on a dedicated GPU row, then launch and retrieve the connection and endpoint key using the lifecycle above. The endpoint speaks the OpenAI audio API: POST {base_url}/audio/transcriptions and POST {base_url}/audio/translations with multipart fields file, model and optionally language, temperature and response_format. Chat routes return 400 route_not_supported. Other speech models are refused at quote time.
curl "$BASE_URL/audio/transcriptions" \
-H "Authorization: Bearer $INFEROPTIMAL_ENDPOINT_KEY" \
-F file=@recording.wav -F model=whisper-large-v3-turbo -F response_format=json
Direct uploads are limited to 100 MB, the edge's request-body limit; a larger body gets 413 request_too_large with these instructions. For recordings up to 512 MiB, upload to storage first and transcribe by reference:
# 1. Ask for an upload URL with the exact file size (valid one hour, for this endpoint only).
curl "$BASE_URL/audio/uploads" \
-H "Authorization: Bearer $INFEROPTIMAL_ENDPOINT_KEY" -H "Content-Type: application/json" \
-d "{\"bytes\": $(wc -c < meeting.wav)}"
# -> {"upload_id": "upl_...", "upload_url": "https://...", "method": "PUT", "headers": {"Content-Length": "..."}}
# 2. PUT the file to upload_url (it goes straight to storage).
curl -X PUT --upload-file meeting.wav "$UPLOAD_URL"
# 3. Transcribe it: the same route, a JSON body naming upload_id instead of a file.
curl "$BASE_URL/audio/transcriptions" \
-H "Authorization: Bearer $INFEROPTIMAL_ENDPOINT_KEY" -H "Content-Type: application/json" \
-d '{"upload_id": "upl_...", "model": "whisper-large-v3-turbo", "response_format": "json"}'
The other JSON fields are passed to the engine as form fields. An upload id only works on the endpoint that issued it, and the stored file is deleted once it has been transcribed; one that is never transcribed is deleted after a day. /audio/translations accepts the same JSON body.
Audio is limited to 2 hours. When a file goes to the engine whole (see below), the engine also refuses audio whose decoded samples exceed 256 MiB, about 70 minutes of 16 kHz mono. Long audio sent to the engine whole loses words: it cuts at fixed 30-second windows (word error rate 3.06% against 1.78% on LibriSpeech test-clean, measured October 22, 2026). The endpoint therefore cuts each transcription at speech pauses first (Silero VAD, pieces of at most 30 seconds, 160 ms minimum silence), transcribes the pieces in parallel and joins the text, for response_format json (the default) and text. Send -F chunking=none to have a file transcribed whole. Translations, verbose_json, srt, vtt and streamed requests go to the engine whole. Transcription responses in json format carry usage.seconds, the duration of the whole input; every audio answer also carries an X-Audio-Duration-Seconds header when the duration is known. The endpoint's audio seconds and request counts appear as audio_usage (unit audio_seconds) in get_deployment stats and get_metrics. Billing is the same as for any dedicated endpoint.
LatentSync 1.6: batch video + audio → MP4
Quote model: "ByteDance/LatentSync-1.6", then launch and retrieve the connection and endpoint key using the lifecycle above. This prepared endpoint runs on InfraOptimal cloud. Use its host as ENDPOINT, without /v1; media jobs use file uploads rather than Chat Completions.
Already launched? Reuse that endpoint and its endpoint key. The optional workload-sizing form is not needed to submit a job. Upload the actual files as multipart fields named video and audio; file paths, URLs or base64 inside JSON are not accepted. Large-file JSON requests use completed upload IDs instead. Let your HTTP client set the multipart Content-Type and boundary.
curl "$ENDPOINT/jobs" \
-H "Authorization: Bearer $INFEROPTIMAL_ENDPOINT_KEY" \
-H "Idempotency-Key: customer-job-001" \
-F video=@face.mp4 -F audio=@speech.wav \
-F steps=20 -F guidance=1.5
The 202 response includes id, status: "queued" and status_url. Save the returned ID as JOB_ID. Reuse the idempotency key with identical inputs when retrying this submission; different inputs with the same key return 409. Use a new key for a different job.
# Poll until status is "completed"; stop on "failed" or "cancelled".
curl "$ENDPOINT/jobs/$JOB_ID" \
-H "Authorization: Bearer $INFEROPTIMAL_ENDPOINT_KEY"
# Download the result after completion.
curl -f "$ENDPOINT/jobs/$JOB_ID/result" \
-H "Authorization: Bearer $INFEROPTIMAL_ENDPOINT_KEY" \
-o lipsynced.mp4
New LatentSync 1.6 endpoints process video in bounded windows, with no fixed clip-duration limit. Multipart uploads allow 32 MiB per input; the client below automatically uses chunked uploads for larger files, up to 2 GiB per input. Video dimensions must not exceed 1920 pixels on either side. Leave enough time in your accepted endpoint lease for the job to finish; runtime and spending limits still apply. Read /runtime for your endpoint’s input and parameter requirements. The endpoint accepts one running job and eight queued jobs; additional submissions return 429. Existing LatentSync 1.5 deployments and its model selector remain supported.
Node.js: automatic upload, status and download
Node 20+. Download the media client beside your script. It uses an existing endpoint and reads its actual /runtime contract, so older endpoints do not silently acquire new capabilities.
import { submitMediaJob } from './media-jobs.mjs';
const job = await submitMediaJob({
baseUrl: process.env.ENDPOINT,
apiKey: process.env.INFEROPTIMAL_ENDPOINT_KEY,
videoPath: './face.mp4', audioPath: './speech.wav',
idempotencyKey: 'customer-job-001',
parameters: { steps: 20, guidance: 1.5 }
});
console.log('Save this job ID:', job.id);
const status = await job.wait({ timeoutMs: 60 * 60 * 1000 });
if (status.status !== 'completed') throw new Error(status.status);
await job.download('./lipsynced.mp4');
Choose a waiting deadline within your endpoint lease. A client timeout only stops waiting; inspect or cancel the saved job explicitly. Stop the endpoint after all jobs finish and results are downloaded.
New LatentSync 1.6 endpoints use speed_mode: "cached" by default. DeepCache reuses intermediate features for faster inference and can change the output. Set speed_mode: "standard" to disable it. Existing endpoints keep their original runtime.
Direct integrations: POST /uploads with {name, bytes, sha256}, send chunks of at most 8 MiB to PUT /uploads/{id}?offset=N, then POST /jobs with {uploads: {video: ID, audio: ID}, parameters: {...}}. Exact chunk retries are idempotent. Inspect or abort staged uploads with GET or DELETE /uploads/{id}. Staging expires after one hour and is limited to 8 GiB per endpoint.
For larger batches, keep excess jobs in your client queue; on 429, wait for a submitted job to finish, or retry with exponential backoff, keeping the same job key and inputs. Download each completed result promptly: it expires one hour after that job finishes, and stopping the endpoint removes access to all results.
Cancel a job or stop the endpoint
DELETE $ENDPOINT/jobs/$JOB_ID with the endpoint key cancels that job. A running job stops at its next denoising callback. Cancellation leaves the endpoint running and billing continues.
# When all jobs are finished, stop the deployment using your platform key.
curl -X POST \
"https://infraoptimal.com/console/api/deployments/$DEPLOYMENT_ID/stop" \
-H "Authorization: Bearer $INFEROPTIMAL_API_KEY" \
-H "Content-Type: application/json" -d '{}'
Accepted Stop ends access and customer billing. Check cleanup.provider_confirmed for hardware release.