API documentation
Mirai v1 exposes a chat completions endpoint. If your code already talks to another backend through that contract, pointing it at this base URL and an API key is usually the only change needed.
Base URL
Every path below is relative to this origin.
https://satuapps.comAuthentication
Every request needs an API key in the Authorization header, using the Bearer scheme. Keep it on the server. Never embed it in a browser or mobile client.
Authorization: Bearer YOUR_API_KEYDon't have a key yet? Contact us.
Chat completions
POST /v1/chat/completions
One call, one answer. There's no session or conversation ID. Send the full message history with every request.
curl https://satuapps.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "mirai-v1",
"messages": [
{"role": "user", "content": "Apa itu basis data relasional?"}
]
}'The response:
{
"id": "chatcmpl-...",
"object": "chat.completion",
"created": 1780000000,
"model": "mirai-v1",
"choices": [
{
"index": 0,
"message": {"role": "assistant", "content": "Basis data relasional adalah ..."},
"finish_reason": "stop"
}
],
"usage": {"prompt_tokens": 24, "completion_tokens": 118, "total_tokens": 142}
}Parameters
| Name | Type | Description |
|---|---|---|
| model | string | One of the model IDs listed below. Defaults to mirai-v1 if omitted. |
| messages | array | Conversation history. Each item has a role (user or assistant) and content. A system message is accepted for wire compatibility but has no effect. Mirai v1 always applies its own system prompt. |
| max_tokens | integer | Upper limit on answer length. Lowers the model's own output budget; never raises it. finish_reason stays "stop" even when this limit cuts the answer short. Length is the only signal you'll get. |
| temperature | number | Answer variability, from 0 (most deterministic) to 2 (most varied). Left unset, the model's own default applies. |
| stream | boolean | If true, the answer is sent as incremental chunks instead of one JSON object. See Streaming below. Default false. |
Images
The last message's content can carry an image alongside text, using the chat completions contract's own format, built from parts: {"type": "image_url", "image_url": {"url": "data:image/png;base64,..."}}. Only data URIs are accepted. Plain https:// links are rejected, so Mirai v1 never fetches a URL on your behalf. Limits: up to 8 images per request, 8 MB each, PNG, JPEG, WebP, or GIF only.
Streaming
Set stream: true to receive the answer as a sequence of server sent events instead of a single JSON object. The stream always ends with a data: [DONE] line.
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1780000000,"model":"mirai-v1","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1780000000,"model":"mirai-v1","choices":[{"index":0,"delta":{"content":"Basis"},"finish_reason":null}]}
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1780000000,"model":"mirai-v1","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: [DONE]The full answer is generated before anything is sent. Streaming changes how it's delivered, not how quickly the first token appears. Expect a similar time to first byte whether stream is on or off.
Add "stream_options": {"include_usage": true} to receive one extra event carrying the token counts, sent right before [DONE].
Models
GET /v1/models Returns every available model and its current pricing, using the same key as chat completions.
| id | Use case | Input per 1M | Output per 1M |
|---|---|---|---|
| mirai-v1-auto | Picks the engine per request | $1.10 | $3.40 |
| mirai-v1 | Everyday work, flat rate | $0.20 | $0.40 |
| mirai-v1-code | Reading and writing code | $1.15 | $3.50 |
| mirai-v1-pro | Long work, high stakes | $1.10 | $3.40 |
Mirai v1 Auto · Mirai v1 · Mirai v1 Code · Mirai v1 Pro
Errors
Authentication, model, quota, and server errors share one JSON shape:
{"error": {"message": "Kunci API tidak ada atau tidak valid.", "type": "authentication_error"}}Message text is always Indonesian, whatever language you're reading this page in. Branch your code on type, not on the message string.
One exception: requests that fail basic validation (malformed JSON, an unsupported image) get FastAPI's default {"detail": ...} body instead of the shape above.
| Code | Meaning |
|---|---|
| 400 | The request body is invalid, usually an image that violates the supported format, size, or count limits. |
| 422 | A required field is missing or the wrong type (for example, an empty messages array). This comes from automatic schema validation, not Mirai v1 logic. |
| 401 | The API key is missing or wrong. The header must be Authorization: Bearer <key>. |
| 403 | This key has been disabled on our end. Contact support. This isn't something you can fix on your end. |
| 404 | The requested model isn't in the public catalogue. The error message itself lists the valid choices. |
| 429 | Requests are being rate limited right now. Wait briefly before retrying. |
| 503 | The service isn't accepting requests at the moment: maintenance, the daily spending cap was reached, or a specific model is temporarily disabled. Retry later. |
| 504 | The request to the model took too long and was cut off. Retry; if it keeps happening, try a different model. |
| 500 | An unexpected error on our side. Rare, and not specific to your request. Retry. |
Health check
GET /health Needs no key and only ever returns {"status":"ok"}. Use it for uptime checks, not for anything that depends on the model backend.
Want to try it before writing any code?
Open the chat interface and paste your key into Settings.
Open chat