Skip to content

POST /v1/render — Submit Render ​

POST /v1/render

Upload an osu! replay file (.osr) with rendering parameters to queue a render job. Returns a job_id for tracking.

Rate Limit: 5 requests per minute per IP

Request ​

Content-Type: multipart/form-data

Parameters ​

FieldTypeRequiredDefaultDescription
replayFile—The .osr replay file
skinstring—DefaultSkin name (alphanumeric, spaces, hyphens, underscores only)
bg_dimfloat—0.95Background dim (0.0 = none, 1.0 = full). Values > 1.0 are auto-normalized (e.g., 95 → 0.95)
resolutionstring—1080pOutput resolution: 1080p or 4k
motion_blurbool—trueEnable motion blur
storyboardbool—trueLoad beatmap storyboard
videobool—falseLoad beatmap background video
snaking_inbool—trueSlider snaking-in animation
snaking_outbool—trueSlider snaking-out animation
hit_error_meterbool—trueShow hit error meter overlay
key_overlaybool—trueShow key press overlay

Example ​

bash
curl -X POST http://localhost:8727/v1/render \
  -F "replay=@my_replay.osr" \
  -F "skin=WhiteCat 1.0" \
  -F "resolution=1080p" \
  -F "bg_dim=0.95" \
  -F "motion_blur=true" \
  -F "storyboard=true" \
  -F "video=false"
python
import httpx

with open("my_replay.osr", "rb") as f:
    resp = httpx.post(
        "http://localhost:8727/v1/render",
        files={"replay": ("replay.osr", f)},
        data={
            "skin": "WhiteCat 1.0",
            "resolution": "1080p",
            "bg_dim": "0.95",
        },
    )
print(resp.json())

Response ​

Status: 202 Accepted

json
{
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "queued",
  "links": {
    "status": "/v1/jobs/550e8400-e29b-41d4-a716-446655440000"
  }
}

Validation Rules ​

The endpoint performs extensive validation before accepting a job:

File Validation ​

  • Extension: Must end in .osr
  • Size: Must not exceed MAX_REPLAY_SIZE_MB (default 50 MB)
  • Not empty: File size must be > 0
  • Structure: Parsed with osrparse to verify replay integrity
  • Game mode: Only osu!standard replays (mode 0) are supported

Parameter Validation ​

  • Skin name: Must match regex ^[a-zA-Z0-9_ -]+$
  • Resolution: Must be 1080p or 4k
  • bg_dim: Must be between 0.0 and 1.0 (auto-normalized if > 1.0)

Capacity Checks ​

  • Global queue: Rejects if MAX_QUEUED (100) jobs are already queued
  • Global rendering: Rejects if MAX_RENDERING (20) jobs are rendering
  • Per-IP limit: Maximum 2 active jobs per IP (enforced via pg_advisory_xact_lock)

Error Responses ​

StatusConditionDetail
400Missing/wrong file extensionFile must be an osu! replay (.osr) file.
400Empty fileUploaded replay file is empty.
413File too largeReplay file exceeds maximum size of 50MB.
415Invalid replay structureInvalid replay file. The structure is corrupted or unsupported.
422Invalid skin name or parametersPydantic validation error
429Rate limit exceededRate limit exceeded: 5 per 1 minute
429Per-IP concurrent limitYou already have 2 active render jobs.
503Queue fullThe render queue is currently full. Please try again later.
503At capacityThe render infrastructure is at maximum capacity.

Admission Control Flow ​

Built with VitePress