Developer API

Text, image, and video endpoints

Send valid requests with text, images, documents and tools, and handle normalized Lato responses for every supported modality.

Updated 30 Sept 2026

POST /messages

Send up to 2000 messages with the system, developer, user, assistant and tool roles. max_tokens defaults to 16384 and goes up to 128000, and reasoning tokens count as output. temperature runs from 0 to 2 and uses the model default when omitted. The response carries usage (including cached input and reasoning tokens), stop_reason, tool_usage and billing.charged_aud, the exact AUD charge for the request. The same request body works on /chat/completions, which answers in the Chat Completions format, and /responses takes the Responses API format. Streaming is not supported yet, so stream:true returns OPMD_MODEL_005.

system and temperature shape the reply; adding stream:true returns 400 OPMD_MODEL_005 instead.
Try this
✦POST /api/v1/messages {"model": "oppermind-lato-1", "system": "You answer as a courteous hotel concierge.", "max_tokens": 200, "temperature": 0.4, "messages": [{"role": "user", "content": "Recommend a quiet place for breakfast near the harbour."}]}
What you getA 200 reply with the concierge answer in content[0].text; adding "stream": true to the same body returns 400 with error.code OPMD_MODEL_005 instead.

Send images and documents

User messages can mix text parts, image_url parts (JPEG, PNG, GIF or WebP as an https URL or a base64 data URL) and file parts for documents: PDF including scanned PDFs, Word (DOCX, DOCM, DOC), Excel (XLSX, XLSM, XLS), PowerPoint (PPTX, PPTM, PPT), OpenDocument (ODT, ODS, ODP), project schedules (Microsoft Project MPP and XML, Primavera P6 XER and XML, MPX), CSV, TXT, MD, JSON and code files. Upload a document once with POST /api/v1/files (raw bytes with an X-Filename header, or JSON with base64 data, up to 31 MB, multipart not supported yet) and send its file_id, or send it inline as base64 file_data with a filename. Microsoft Project .mpp files are read as a task table.

Upload once, then reference the file_id in any text request. An account keeps up to 1000 files and 10 GiB.
Try this
✦POST /api/v1/files with the raw bytes of lease.pdf and the header X-Filename: lease.pdf, then POST /api/v1/messages {"model": "oppermind-lato-1", "messages": [{"role": "user", "content": [{"type": "text", "text": "List the break clauses in this lease."}, {"type": "file", "file": {"file_id": "file-7d2c9a4e1b6f8c3a5e0d9b2f4a6c8e1d"}}]}]}
What you getThe upload returns a file object with its id, and the message reply lists the break clauses from the PDF. The same file_id works in later requests until you delete it.

Call functions and built-in tools

Send tools with type function (a name, a description and JSON Schema parameters), plus tool_choice and parallel_tool_calls. When the model calls a function, the reply holds tool_use content blocks and stop_reason is tool_use. Run the function, repeat the call in an assistant message with tool_calls, and send the result in a tool message with the matching tool_call_id. The built-in tools are web_search (optionally limited to allowed or excluded domains), x_search, code_interpreter and mcp for remote MCP servers. Their calls are counted in tool_usage and billed per call. A tool or option the current model version cannot use returns 400 OPMD_CAPABILITY_001 with a message that names it.

stop_reason tool_use means run the function, then send a tool message with the same tool_call_id.
Try this
✦POST /api/v1/messages {"model": "oppermind-lato-1", "tools": [{"type": "function", "function": {"name": "get_order_status", "parameters": {"type": "object", "properties": {"order_id": {"type": "string"}}, "required": ["order_id"]}}}], "messages": [{"role": "user", "content": "Where is order 58213?"}]}
What you getThe reply has a tool_use block that asks for get_order_status with order_id 58213. Your code looks the order up and sends the answer back as a tool message, and the next reply tells the customer where the order is.

POST /images

Send a prompt of up to 8 KB and choose a count from 1 to 4, standard or HD quality, URL or b64_json response format, aspect ratio, and resolution. Counts outside 1 to 4 are clamped, and some options may not apply on every model version.

Two entries, each an authenticated proxy URL you fetch with the same bearer. n is capped at four.
Try this
✦POST /api/v1/images {"prompt": "minimalist poster for a community bike repair workshop, teal and cream", "n": 2, "quality": "hd", "aspect_ratio": "3:4", "response_format": "url"}
What you getThe data array holds two entries, each with a url you fetch using the same Bearer key. A request with n above 4 still returns at most four images, so keep the count at four or fewer.

POST /videos

Send a prompt, a duration from 1 to 15 seconds (default 10, values outside the range are clamped), and 720p or 1080p. Generation is synchronous, so allow a generous timeout and use the finished URL in the POST response. Billing uses the delivered duration.

The response waits for the finished video; status is always succeeded and there is nothing to poll.
Try this
✦POST /api/v1/videos with a client timeout of at least 120 seconds {"prompt": "slow aerial pan over rows of solar panels at sunrise", "duration_seconds": 8, "resolution": "1080p"}
What you getAfter the wait, the 200 body arrives with status succeeded, a url, duration_seconds and resolution; there is no job to poll, and the key must have Full Access.

Fetch protected video output

The returned video URL is an Oppermind proxy path. Fetch it with the same Bearer API key. GET /videos/{id} is a compatibility confirmation - not a polling requirement.

Same bearer, video bytes back; GET /videos/{id} only confirms generation was synchronous.
Try this
✦curl 'https://oppermind.com/api/v1/videos/proxy?token=…' -H 'Authorization: Bearer opmd_sk_…' -o solar.mp4 using the url value from the POST response.
What you getThe video bytes download to solar.mp4; the same request without the Authorization header is refused, and GET /videos/{id} only returns a note that generation was synchronous.

Use normalized responses

Responses expose Oppermind Lato model identifiers. Capture content, usage (including cached input and reasoning tokens), tool_usage, billing.charged_aud, request ID, route type, and API version.

Log body.model, body.usage and these headers; an upstream provider name never appears.
Try this
✦Log these from every response: body.model, body.usage, body.billing.charged_aud, and the headers X-Request-ID, X-Route-Type and X-API-Version.
What you getYour logs show model values such as oppermind-lato-1 and oppermind-lato-1-video, never an upstream provider name, next to a request ID you can quote to support.
GUIDED LEARNING

Practise this in Oppermind Academy

Follow the related tutorial or course and apply the concept to a real task.

Open learning path