Sign in

Docs

Miru API

Render osu!mania replays from your bot or your tooling.

How a render goes

Four steps, and only the first one writes anything. A bot that follows them needs nothing else.

  1. 1

    You send the replay

    POST /renders with the .osr as multipart. It answers 202 with an id before the render starts.

  2. 2

    You wait

    Register a callbackUrl and Miru calls you when it is done, or poll GET /renders/:id every few seconds.

  3. 3

    You read the result

    status turns COMPLETED and output carries the video URL, which expires: download it or keep your own copy.

  4. 4

    If it went wrong

    status turns FAILED with an error object. Anything still queued is cancelled with DELETE /renders/:id.

Authentication

Create a key in your account settings and send it in the header. It is shown only once.

Authorization: Bearer mk_live_...

Quickstart

Upload an .osr and poll until it is done.

Endpoints

post/api/v1/renders

Crear un render

Se manda el `.osr` como multipart en el campo `replay`. Manda `Idempotency-Key` si quieres que un reintento de red no genere dos renders: con la misma clave, la segunda llamada devuelve el mismo render con `200` en vez de `202`.

get/api/v1/renders

Listar tus renders

Paginado por cursor: pasa el `nextCursor` de la respuesta anterior.

get/api/v1/renders/{id}

Estado de un render

delete/api/v1/renders/{id}

Cancelar un render

Solo si sigue en cola o procesando.

get/api/v1/quota

Cuánto te queda

No consume cuota. Sirve para que un bot se autorregule.

get/api/v1/skins

Tus skins

Los ids que acepta `skinId` al crear un render. Solo las ya procesadas.

get/api/v1/presets

Tus presets

Los ids que acepta `presetId` al crear un render.

get/api/v1/status

Estado de la cola

Público: no necesita key.

The full spec, to generate clients or import into Postman: openapi.json

The render object

What every endpoint returns inside data. Fields that stay null until the render reaches their stage are still there as null, they do not disappear.

data

idstring (uuid)
status"QUEUED" | "PROCESSING" | "COMPLETED" | "FAILED" | "CANCELLED"
progressinteger
phasestringnull
resolution"720p60" | "1080p60"
beatmapobject
outputobjectnullSolo cuando el render terminó. La URL vence.
errorobjectnull
createdAtstring (date-time)
startedAtstring,null (date-time)
completedAtstring,null (date-time)

The states it goes through

QUEUED and PROCESSING are the ones that keep moving. The other three are final: a render never leaves them.

QUEUEDPROCESSINGCOMPLETEDFAILEDCANCELLED

Idempotency

Send Idempotency-Key and a network retry will not create two renders: the second call returns the same one, with 200 instead of 202.

Webhooks

Instead of polling, register a callbackUrl when you create the render and we will tell you when it is done.

Always verify the signature

Every delivery is signed with HMAC-SHA256 in X-Miru-Signature, using your key secret. Without verifying it, anyone who knows your URL can send you a fake notification.

Retries

Five retries within an hour if your server does not answer. X-Miru-Delivery carries a unique id so you can drop duplicates.

Limits

Per key and per hour, on free accounts only. They ride in the headers of every response so your bot can stop before the 429; with Plus there is no cap and those headers are not sent.

PlanRenders per hourConcurrentResolutionWebhooks
Free101720p60No
PlusNo capNo cap1080p60Yes

Errors

Always the same shape. Compare against code, which is stable; the message can change.

CodeHTTPWhen
UNAUTHORIZED401The key is missing, malformed or revoked.
FORBIDDEN403The key is valid but your plan does not allow that.
NOT_FOUND404That render does not exist, or is not yours.
VALIDATION_ERROR400Something in the request does not match what the endpoint takes.
RATE_LIMITED429You ran out of renders for the hour. Retry-After says how long.
ACTIVE_RENDER_LIMIT403You already have as many renders going at once as your plan allows.
CONFLICT409The render had already finished, so there is nothing to cancel.