Workspace/API documentation
DEVELOPER DOCUMENTATION

Mimochi API

Connect your application to chat, image, and video models.

Manage API keys
v1 · HTTPS · Server-to-server

Quickstart

Use one Mimochi API key for text, image, and video generation. API requests use the same service-credit balance and holder eligibility as your Mimochi account.

Base URL: https://mimochi.si/v1

  1. Connect your wallet and create an API key.
  2. Enable read plus the generation services your application needs. Set a lifetime budget, a per-request limit, and an optional expiry.
  3. Store the key in your server environment. Add credits in Wallet & usage for paid models.
  4. Read the catalog, choose a model, and send a request with a unique idempotency key.

Set up your server environment

bash
export MIMOCHI_API_KEY='YOUR_SERVER_API_KEY'
export MIMOCHI_BASE_URL='https://mimochi.si/v1'

Do not expose your key in browser code, mobile app bundles, URLs, or public repositories. Requests are intended for your backend; browser cross-origin access is not supported.

Find a chat model

bash
curl --fail-with-body "$MIMOCHI_BASE_URL/models?kind=chat" \
  -H "Authorization: Bearer $MIMOCHI_API_KEY"

Copy a model's full id into MIMOCHI_MODEL. IDs include their service prefix, such as chat:. The placeholder below must be replaced with an ID returned by your catalog.

bash
export MIMOCHI_MODEL='chat:MODEL_ID_FROM_CATALOG'

Make a text request

bash
curl --fail-with-body "$MIMOCHI_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $MIMOCHI_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: welcome-chat-0001' \
  --data "{\"model\":\"$MIMOCHI_MODEL\",\"messages\":[{\"role\":\"user\",\"content\":\"Write a short welcome message.\"}],\"max_tokens\":256,\"max_cost\":\"0.10\"}"

max_cost is your credit reservation ceiling, not a price estimate. Choose a budget that fits the selected model and requested output. If it is too low, the request is rejected before generation. Change the idempotency key for a new generation; reuse it unchanged only when retrying the same request.

A completed request returns HTTP 200 with choices[0].message.content. A request still running after the connection window returns HTTP 202 with a job. Continue through that job's links.self; do not submit a new paid request.

Node.js · built-in fetch

javascript
// Node.js 22+. Set MIMOCHI_API_KEY and MIMOCHI_MODEL on your server.
import { randomUUID } from 'node:crypto';
const base = 'https://mimochi.si/v1';
const headers = {
  Authorization: `Bearer ${process.env.MIMOCHI_API_KEY}`,
  'Content-Type': 'application/json',
  'Idempotency-Key': randomUUID(),
};
const response = await fetch(`${base}/chat/completions`, {
  method: 'POST', headers,
  body: JSON.stringify({
    model: process.env.MIMOCHI_MODEL,
    messages: [{ role: 'user', content: 'Write a short welcome message.' }],
    max_tokens: 256, max_cost: '0.10',
  }),
});
const result = await response.json();
if (!response.ok) throw new Error(result.error?.message ?? `HTTP ${response.status}`);
if (response.status === 202) {
  console.log('Continue with this job:', result.id, result.links.self);
} else {
  console.log(result.choices[0].message.content);
  console.log('Job for final billing:', result.mimochi.job_id);
}

Keep the same idempotency key and request body if your request times out. A new UUID starts a different generation.

Python · standard library

python
# Set MIMOCHI_API_KEY and MIMOCHI_MODEL in the server environment.
import json
import os
import uuid
import urllib.request
import urllib.error

body = {
    "model": os.environ["MIMOCHI_MODEL"],
    "messages": [{"role": "user", "content": "Write a short welcome message."}],
    "max_tokens": 256,
    "max_cost": "0.10",
}
request = urllib.request.Request(
    "https://mimochi.si/v1/chat/completions",
    data=json.dumps(body).encode(),
    headers={
        "Authorization": "Bearer " + os.environ["MIMOCHI_API_KEY"],
        "Content-Type": "application/json",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    method="POST",
)
try:
    with urllib.request.urlopen(request, timeout=70) as response:
        result = json.load(response)
        if response.status == 202:
            print("Continue with this job:", result["id"], result["links"]["self"])
        else:
            print(result["choices"][0]["message"]["content"])
            print("Job for final billing:", result["mimochi"]["job_id"])
except urllib.error.HTTPError as error:
    print("HTTP", error.code, error.read().decode())

Keys & permissions

Every /v1 endpoint requires an API key in the request header:

http
Authorization: Bearer YOUR_SERVER_API_KEY

Create and revoke keys in API access after signing in with your wallet. The full secret is shown once; it cannot be retrieved later. A lost key should be revoked and replaced.

PermissionAccess
readModels, generation options, rates, job status and events, asset downloads, balance, and usage
chatChat generation; cancellation also requires read
imageImage generation and media uploads
videoVideo generation and media uploads

For the full generation workflow, grant read together with the relevant service permission. An optional model allowlist restricts generation to specific catalog IDs. Leaving the list empty allows models within the key's service permissions.

Each key has a lifetime spending limit, a per-request limit, and a request rate limit. The default lifetime limit is 10 credits and the default per-request limit is 1 credit. A lifetime limit can be at most 1,000,000 credits; the per-request limit cannot exceed it. Requests per minute can be set from 1 to 120; the default is 60. Read requests and job polling also count toward this rate. Additional service limits apply: up to 6 chat submissions per key per minute, 12 job-event connections per key per minute, and 6 uploads per account per minute. Chat submissions (streaming and non-streaming) and job-event connections also share a combined limit of 12 connections per minute per account across all API keys. This account connection limit is checked before a new generation is accepted. Account-wide active-job limits also apply. At most 20 active keys can exist for one account. Use an expiry when access should end automatically.

Jobs, uploads, assets, and usage belong to the key that created them. Another key on the same account cannot retrieve those API resources. All keys share the account's service-credit balance, but each key has its own spending budget.

Revoking a key blocks new requests immediately. Existing generation jobs may still complete and settle against the account. Revoke and replace a key to change its permissions or limits; key editing is not available in this version.

The API accepts server-to-server requests. Do not send an Origin header or make API calls directly from a browser. Put your own authenticated application backend between your users and Mimochi.

Models & rates

Read model IDs and capabilities from the catalog instead of hard-coding model assumptions. Availability and supported configurations can change.

MethodEndpointPurpose
GET/modelsList models visible to this key
GET/models?kind=chatFilter by chat, image, or video
GET/models/options?model=MODEL_IDSupported parameters, defaults, and required media inputs
GET/models/rates?model=MODEL_IDPublished unit rates in credits
bash
curl --fail-with-body --get "$MIMOCHI_BASE_URL/models/options" \
  -H "Authorization: Bearer $MIMOCHI_API_KEY" \
  --data-urlencode "model=$MIMOCHI_MODEL"

curl --fail-with-body --get "$MIMOCHI_BASE_URL/models/rates" \
  -H "Authorization: Bearer $MIMOCHI_API_KEY" \
  --data-urlencode "model=$MIMOCHI_MODEL"

The model list returns { "object": "list", "data": [...] }. Each entry includes its id, name, kind, available, context length, modalities, discount cap, and published pricing information. Chat input is text only. Catalog available describes platform availability (availability_scope: "platform"); it does not guarantee every API request is supported.

The options response uses API parameter names such as aspect_ratio, output_format, and generate_audio. Read parameters for permitted values and ranges, defaults for default values, inputs for media requirements, and prompt_required for whether a prompt is needed.

Check the options response's available, platform_available, and api_budget_support fields. An api_budget_support value of unsupported means the configuration cannot currently run through the API. A value of request_dependent requires validation of the actual request. Only send settings returned for the model. A model listed in the catalog may not support a particular combination of resolution, duration, reference inputs, or cost controls. API submission validates the exact request. api_budget_unsupported means that configuration cannot currently run with an enforceable API allowance; choose a different model or configuration.

The rates response contains model, currency: "credits", and lines. Each line contains its label, decimal amount, unit, and an optional note.

Published token rates are unit prices, not the cost of an entire request. Final billing uses verified actual usage. Holder discounts depend on your account's eligibility and the model's discount cap.

Chat & streaming

POST /chat/completions

Send the conversation history with every request. This is a text-only chat endpoint with familiar chat-completion request and response fields. It is a supported subset, not a claim that every option in another SDK is accepted.

FieldRequiredDescription
modelYesFull chat: model ID from the catalog
messagesYes1–100 messages with role and text content
max_costYesDecimal string in credits, with up to six decimal places
max_tokensNoInteger from 1 to 65,536, subject to model support
streamNofalse by default; true returns server-sent events

Allowed roles are system, user, and assistant. The last message must be a user message. Each content string is non-empty and at most 8,000 characters; total content must be at most 48,000 UTF-8 bytes. The model's context limit also applies. The JSON request body must fit within 65,536 bytes. Unsupported fields are rejected rather than silently ignored.

This version does not accept images, videos, audio, files, tools, function calling, JSON schema output, or a temperature field in chat requests. Use the image and video endpoints for media generation.

Completion response

A completed response includes id, object: "chat.completion", model, choices, usage, and mimochi. Read the answer from choices[0].message.content. usage may be null while verified token counts are unavailable. mimochi.job_id and mimochi.status_url identify the saved job; check that job for final billing.

The connection waits for up to roughly 55 seconds. If the work has not finished, HTTP 202 returns a generation.job response with Location and Retry-After headers. The job continues after the response.

Streaming

bash
curl --no-buffer --fail-with-body "$MIMOCHI_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $MIMOCHI_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: welcome-stream-0001' \
  --data "{\"model\":\"$MIMOCHI_MODEL\",\"messages\":[{\"role\":\"user\",\"content\":\"Explain the idea in three short paragraphs.\"}],\"max_tokens\":512,\"max_cost\":\"0.10\",\"stream\":true}"

Read data: JSON events and append choices[].delta.content. A completed stream sends a final choice, a usage chunk when verified counts are available, then data: [DONE]. Comment lines beginning with : are keepalives.

Named error and timeout events are not successful completion and do not send [DONE]. The event includes the existing job ID or status URL. Save the x-mimochi-job-id response header as soon as the connection opens. On timeout or disconnection, retrieve that job instead of creating a replacement generation.

Replaying a streaming request can resend already saved text. Reconstruct the message from the recovered job or replace the displayed content; do not blindly append a replay to an existing partial response. Closing the connection does not cancel the generation.

Image generation

POST /images/generations

Image generation is asynchronous. The response is HTTP 202 with a job ID, not an immediate list of public image URLs. Poll the saved job and download its assets once available.

Choose an image: model from the catalog, then read its options. Set MIMOCHI_IMAGE_MODEL to that exact ID.

bash
export MIMOCHI_IMAGE_MODEL='image:MODEL_ID_FROM_CATALOG'

curl --fail-with-body "$MIMOCHI_BASE_URL/images/generations" \
  -H "Authorization: Bearer $MIMOCHI_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: product-image-0001' \
  --data "{\"model\":\"$MIMOCHI_IMAGE_MODEL\",\"prompt\":\"A ceramic cup photographed on a neutral studio background.\",\"max_cost\":\"1.00\",\"parameters\":{}}"

The empty parameters object uses supported defaults. Add only the values published by /models/options: for example resolution, aspect_ratio, quality, output_format, or count when the chosen model supports them. Image count can be 1–4, subject to model limits.

For reference or editing workflows, upload the image first and place the returned upload ID in parameters.upload_ids. The selected model must explicitly support reference images. For example, the parameters shape is { "upload_ids": ["UPLOAD_ID"] }.

A model whose pricing cannot be bounded safely for an API request returns api_budget_unsupported. A published rate alone does not guarantee support for every API configuration. An image request may be available in the website while this API configuration is unavailable.

Video generation

POST /videos

Video generation is asynchronous. Submit once, save the returned job ID, and check the job's status. The video: model determines which text, image-reference, video-reference, or audio-reference workflows are supported.

bash
export MIMOCHI_VIDEO_MODEL='video:MODEL_ID_FROM_CATALOG'

curl --fail-with-body "$MIMOCHI_BASE_URL/videos" \
  -H "Authorization: Bearer $MIMOCHI_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: product-video-0001' \
  --data "{\"model\":\"$MIMOCHI_VIDEO_MODEL\",\"prompt\":\"A slow camera move around a ceramic cup in soft studio light.\",\"max_cost\":\"1.00\",\"parameters\":{}}"

This example uses defaults and a sample budget. Read model options first: a model may require references, and its selected configuration may need a higher budget. If prompt_required is false, send an empty prompt string when your workflow does not use one.

ParameterUse when supported
durationRequested output length in seconds
resolution, aspect_ratioOutput dimensions or shape
generate_audioGenerate audio along with the video
upload_idsUploaded reference images; at most three, with model-specific limits
reference_modereference or frames, according to the model
source_video_idUploaded source video for editing or upscaling
audio_upload_idUploaded speech/audio reference
upscale_factor, creativityModel-specific transformation controls

The API validates media dimensions, duration, format, and the pricing of the selected configuration. Unsupported combinations are rejected before generation.

Poll jobs or use the job event stream to track progress. This version does not provide outgoing completion webhooks or video cancellation.

Uploads & downloads

Upload reference media with POST /uploads using multipart/form-data and exactly one file field. Use the same API key for uploading, generation, and downloading the results.

bash
curl --fail-with-body "$MIMOCHI_BASE_URL/uploads" \
  -H "Authorization: Bearer $MIMOCHI_API_KEY" \
  -F 'file=@reference.png;type=image/png'

The response includes the upload's id, verified media metadata, and expiry. Use its ID in upload_ids, source_video_id, or audio_upload_id, depending on the model. Read /models/options for accepted MIME types, file size limits, and required input counts. General limits are 10 MiB for reference images, 30 MB for audio, and 150 MB for video; a particular model can impose stricter limits.

Remote URLs and base64 media are not accepted as generation inputs. Upload actual media bytes. The API checks the file contents and model-specific requirements.

bash
# Remove an input upload you no longer need.
curl --fail-with-body -X DELETE \
  "$MIMOCHI_BASE_URL/uploads/UPLOAD_ID" \
  -H "Authorization: Bearer $MIMOCHI_API_KEY"

Deleting a reference can affect a request that has not finished using it. Wait for dependent jobs to finish before deleting it.

Completed media jobs contain output.assets. Each asset includes an id, mime_type, filename, expires_at, and content_url. These URLs require API authentication; they are not public links.

bash
# Replace ASSET_ID with an ID from your completed job.
curl --fail-with-body "$MIMOCHI_BASE_URL/assets/ASSET_ID/content" \
  -H "Authorization: Bearer $MIMOCHI_API_KEY" \
  --output generated-media.bin

Choose a filename extension matching the asset's mime_type. Downloads support HTTP range requests for video. Retrieve media on your server and deliver it through your own application; never put a Mimochi API key in a public download URL.

Media is normally retained for 30 days. Treat each asset's expires_at as authoritative and save the files you need before they expire.

Jobs & recovery

Use the job ID returned by a generation request to recover progress, output, and final billing.

MethodEndpointPurpose
GET/jobs/JOB_IDRead status, output, assets, and billing
GET/jobs/JOB_ID/eventsServer-sent snapshots of the saved job
POST/jobs/JOB_ID/cancelRequest cancellation of a chat job
bash
curl --fail-with-body "$MIMOCHI_BASE_URL/jobs/JOB_ID" \
  -H "Authorization: Bearer $MIMOCHI_API_KEY"

curl --no-buffer --fail-with-body "$MIMOCHI_BASE_URL/jobs/JOB_ID/events" \
  -H "Authorization: Bearer $MIMOCHI_API_KEY"

A job response has object: "generation.job", id, kind, model, status, timestamps, output, usage, billing, error, and recovery links. Text appears in output.text; images and video appear in output.assets. output.expired indicates when retained output is no longer available. Billing records can remain after output expires. Replaying a completed chat after its retained text expires returns HTTP 410 with content_expired; it does not start a new generation. A stream reports the same condition as an error event without [DONE].

Typical progress is queued → submitting → running → storing → completed, although some services skip stages. failed and cancelled describe unsuccessful or cancelled generation. submission_unknown, needs_review, and storage_failed need verification or recovery; continue checking the existing job and avoid duplicate paid submissions.

Job events use event: snapshot with the full current job as data. Save each event's id and send it in Last-Event-ID when reconnecting to avoid receiving the same unchanged snapshot. This is a current-state stream, not a historical event log. Connections are bounded; reconnect or poll when they end. Poll every few seconds and slow down for long jobs, since polling counts against the key's rate limit.

Generation completion and billing settlement are separate. A completed output can still have pending billing. Check billing.status; billing.cost is null until the final customer charge is settled. If an administrator returns service credits, billing.cost becomes "0" and the response includes original_cost and refunded. billing.reserved is the remaining temporary hold, in credits.

bash
# Chat only. Cancellation is best effort and does not erase incurred usage.
curl --fail-with-body -X POST \
  "$MIMOCHI_BASE_URL/jobs/JOB_ID/cancel" \
  -H "Authorization: Bearer $MIMOCHI_API_KEY"

Closing a client connection does not cancel its job. Do not assume a failed HTTP connection means no generation was accepted.

Balance, usage & limits

GET /balance returns the shared account balance and the current key's budget information. GET /usage lists generation records created by the current key.

bash
curl --fail-with-body "$MIMOCHI_BASE_URL/balance" \
  -H "Authorization: Bearer $MIMOCHI_API_KEY"

curl --fail-with-body "$MIMOCHI_BASE_URL/usage?limit=20" \
  -H "Authorization: Bearer $MIMOCHI_API_KEY"

The balance response contains object: "balance", currency: "credits", and account available, reserved, and spent amounts. The nested api_key object contains id, spend_limit, spent, reserved, remaining, and per_request_limit. All amounts are decimal strings.

Usage returns { "object": "list", "data": [...], "has_more": false, "next_cursor": null }. Each record includes id, kind, model, status, created_at, verified token usage when available, and billing. The default page size is 25; limit accepts 1–100. When has_more is true, pass the exact next_cursor as the next request's cursor query parameter.

bash
# Replace NEXT_CURSOR with the cursor from the previous response.
curl --fail-with-body --get "$MIMOCHI_BASE_URL/usage" \
  -H "Authorization: Bearer $MIMOCHI_API_KEY" \
  --data-urlencode 'limit=20' \
  --data-urlencode 'cursor=NEXT_CURSOR'

How a request uses credits

  1. Send a max_cost decimal string with every generation request. It cannot exceed your key's per-request limit.
  2. Mimochi checks the model and configuration, computes a conservative internal allowance, and validates the request budget, key lifetime budget, and available account credits.
  3. Accepted work reserves credits for that request. Other requests can use the remaining available balance, subject to their own limits.
  4. Verified actual usage determines the final charge. Eligible holder discounts apply, and unused held credits are released.

max_cost is a reservation ceiling and authorization limit. It is not a quote, a fee, or a promise that the generation will consume that amount. Lower max_tokens, shorten the input, or choose a less expensive configuration if a request cannot fit your budget. A configuration without enforceable cost controls is rejected.

The unit is credits: 1 credit = 1 USDG, with USD pricing accounted for at 1:1. No platform markup is added. A zero max_cost is accepted only for a verified free request. A key with zero lifetime and per-request budgets is limited to those free requests.

Your applied holder discount depends on current eligibility and the selected model's cap. For example, a verified cost of 0.10 credits with an applied 50% discount results in a 0.05 credit charge. The maximum advertised discount is not automatically the discount on every account or model.

The website and every API key share one balance. Key limits do not allocate extra credits. Reserved amounts count against available key budget until settlement. A lifetime limit does not reset each month. Existing jobs continue to settle if a key expires or is revoked.

Account balances do not become negative. If a verified charge exceeds the held amount, the discrepancy enters review rather than creating a negative user balance. Do not treat an unresolved or null charge as free usage.

Top-ups remain available through Wallet & usage. This developer API does not expose payment signing or a refund endpoint.

Idempotency & retries

Every generation submission requires an Idempotency-Key header. Use 8–128 letters, digits, hyphens, or underscores. A UUID is a suitable choice.

Reuse the same key and the same generation body after a timeout, a disconnected stream, or an uncertain HTTP response. Mimochi recovers the existing accepted job instead of starting another generation. Reusing the key with different generation data returns HTTP 409 with idempotency_conflict. Changing stream alone can recover the same generation using the other transport mode.

Save the idempotency key, original request body, and returned job ID in your application before retrying. A new idempotency key authorizes a new generation and can create an additional charge. Do not automatically retry a failed or uncertain generation with a fresh key.

For HTTP 429, wait for Retry-After when provided and back off between retries. For transient 5xx or network errors, use bounded exponential backoff and the original generation key. Once you know the job ID, status polling is preferable to repeated submissions. Do not retry 401, 403, 402, or validation errors without correcting their cause.

Idempotency applies to generation submissions. Uploads are separate resources; retrying a multipart upload can create a new upload ID. Reuse an existing upload when it has already been returned successfully.

Errors & endpoint reference

Errors use an error object with a code and human-readable message. Read error.request_id or the x-request-id response header for the request reference. Public API error codes use lowercase, such as api_budget_too_low. Never include your full API key when reporting an error.

HTTP statusMeaningAction
401Missing, invalid, expired, or revoked keyCheck authentication or replace the key
402Insufficient credits or exhausted key budgetAdd credits or create a key with an appropriate budget
403Missing permission, disallowed model, or browser requestCheck scopes, model allowlist, and backend use
404Resource absent, expired, or unavailable to this keyCheck the ID and the key that created it
409Idempotency conflict or generation state conflictRecover the original job and check its status
410Previously generated chat output has expiredUse your saved output; a replay does not regenerate it
413Payload or upload too largeReduce request or file size
415Unsupported content typeUse JSON or the documented multipart format
422Invalid fields, unsupported configuration, or insufficient request allowanceCheck model options and the error code
429Rate limit reachedBack off; respect Retry-After when supplied
5xxTemporary service or infrastructure failureRetry safely with the original idempotency key

Useful budget codes include api_request_limit when max_cost exceeds the key's per-request limit, api_spend_limit when the key's lifetime budget is exhausted, api_budget_too_low when a configuration cannot fit the request allowance, and api_budget_unsupported when that configuration cannot be safely bounded for API use.

Full endpoint list

MethodEndpointPermission
GET/modelsread
GET/models/optionsread
GET/models/ratesread
POST/chat/completionschat
POST/images/generationsimage
POST/videosvideo
POST/uploadsimage or video
DELETE/uploads/UPLOAD_IDimage or video
GET/jobs/JOB_IDread
GET/jobs/JOB_ID/eventsread
POST/jobs/JOB_ID/cancelread + chat
GET/assets/ASSET_ID/contentread
GET/balanceread
GET/usageread

All paths above are relative to https://mimochi.si/v1. Generation permissions are necessary in addition to model eligibility and budget checks. Catalog entries do not override these checks.