Panduan Midjourney API Python: buat dan simpan gambar
Buat tugas, periksa sampai selesai, lalu simpan satu grid PNG 2x2; kunci dan body tersimpan di disk sebelum POST.
Di halaman ini
- Jawaban singkat
- API mana yang dipakai contoh Python ini?
- Yang Anda butuhkan
- Body permintaan dan parameter
- Memanggil Midjourney API dari Python
- Grid gambar Midjourney yang dikembalikan
- Menjalankan ulang setelah timeout atau unduhan gagal
- Error dan perbaikan
- Biaya dan kapan memakai API gambar lain
- Pertanyaan umum
- Apakah saya perlu langganan Midjourney untuk memakai API ini?
- Mengapa satu tugas Midjourney mengembalikan empat gambar dalam satu file?
- Apa arti 409 idempotency_key_reused?
- Apa yang terjadi jika skrip saya timeout saat memeriksa status?
Contoh ini memanggil API Midjourney pihak ketiga dari OmniaKey melalui Python dalam tiga langkah: buat tugas, periksa statusnya sampai selesai, lalu unduh PNG dari URL aset bertanda tangan. Uji integrasi 12 November 2026 mengembalikan satu gambar 2048x2048 dalam 197,1 detik, dan gambar itu adalah grid 2x2 berisi empat kandidat. Skrip di bawah menambahkan file status, sehingga timeout atau unduhan gagal tidak membuat tugas berbayar kedua.
Jawaban singkat
- Kirim
POST https://api.omniakey.com/v1/media/tasksdenganIdempotency-Key, lalu periksaGET /v1/media/tasks/{id}dan unduhassets[0].url. - Satu tugas mengembalikan satu grid PNG berisi empat gambar, bukan empat file terpisah.
- Midjourney di API ini hanya teks ke gambar: tanpa edit, gambar referensi, blend, upscale, vary, geser, atau pemilih versi.
- Kunci berasal dari OmniaKey dan terpisah dari langganan Midjourney. Simpan body dan kunci idempotensi sebelum POST, tambahkan id tugas setelah API menerima, dan pertahankan file status untuk melanjutkan nanti. Timeout lokal tidak membatalkan tugas di server.
API mana yang dipakai contoh Python ini?
Contoh memanggil API pihak ketiga OmniaKey untuk Midjourney. OmniaKey bukan Midjourney, dan kunci OmniaKey adalah akun terpisah dengan saldo sendiri. Langganan di situs Midjourney adalah produk lain dan tidak membuat kunci OmniaKey.
Halaman model Midjourney menampilkan model dan tarif saat ini di sisi OmniaKey. Bagian berikutnya membahas integrasi ini dan siklus hidup tugasnya.
Yang Anda butuhkan
Anda membutuhkan tiga hal:
- Kunci API OmniaKey, diekspor sebagai
OMNIAKEY_API_KEY. - Python 3. Skrip hanya memakai pustaka standar, jadi tidak ada SDK yang perlu dipasang.
midjourneytersedia untuk kunci/akun itu. Jika model tidak ada di daftar kunci, periksa akses akun sebelum menjalankan panggilan pembuatan.
export OMNIAKEY_API_KEY="your-key"
python3 midjourney_grid.py
Jauhkan kunci dari skrip dan log. Kode membacanya sekali dari environment.
Body permintaan dan parameter
Midjourney menerima prompt dan tiga parameter. Tipe bot sudah diatur di sisi OmniaKey, jadi body bisa melewati versi model dan botType.
| Kolom | Nilai | Catatan |
|---|---|---|
input.prompt | Teks | Adegan yang diinginkan |
parameters.aspectRatio | 1:1 | Juga 16:9, 9:16, 3:2, 2:3 |
parameters.quality | "1" | Dokumentasi memakai string "1" |
parameters.n | 1 | Harus 1 |
Tentukan bentuk dengan aspectRatio, bukan ukuran piksel. Kolomnya camelCase: aspectRatio, bukan aspect_ratio. Pakai salah satu dari lima nilai yang terdaftar.
Body untuk prompt contoh terlihat seperti ini:
{
"model": "midjourney",
"type": "image",
"operation": "generate",
"input": {
"prompt": "A small red paper boat floating on a quiet blue lake at sunrise, cinematic lighting, elegant composition, no text"
},
"parameters": {"aspectRatio": "1:1", "quality": "1", "n": 1}
}
Memanggil Midjourney API dari Python
Simpan sebagai midjourney_grid.py dan jalankan. Eksekusi pertama menulis midjourney-task.json sebelum POST, lalu menambahkan id tugas setelah OmniaKey menerima permintaan.
import hashlib
import json
import os
import sys
import time
import urllib.error
import urllib.request
import uuid
from pathlib import Path
API = "https://api.omniakey.com/v1"
KEY = os.environ["OMNIAKEY_API_KEY"]
STATE = Path("midjourney-task.json")
OUT = Path("midjourney-grid.png")
PROMPT = ("A small red paper boat floating on a quiet blue lake at sunrise, "
"cinematic lighting, elegant composition, no text")
def save(state):
tmp = STATE.with_suffix(".tmp")
tmp.write_text(json.dumps(state, indent=2))
tmp.replace(STATE)
def read_json(response):
raw = response.read()
try:
return json.loads(raw)
except ValueError:
return {"raw": raw[:300].decode("utf-8", "replace")}
def call(method, path, body=None, headers=None):
data = json.dumps(body).encode() if body is not None else None
req = urllib.request.Request(
API + path, data=data, method=method,
headers={"Authorization": f"Bearer {KEY}", **(headers or {})})
if body is not None:
req.add_header("Content-Type", "application/json")
try:
with urllib.request.urlopen(req, timeout=60) as response:
return response.status, read_json(response)
except urllib.error.HTTPError as error:
return error.code, read_json(error)
except (urllib.error.URLError, TimeoutError) as error:
return None, {"error": str(error)}
def main():
state = json.loads(STATE.read_text()) if STATE.exists() else None
if state is None:
body = {
"model": "midjourney", "type": "image", "operation": "generate",
"input": {"prompt": PROMPT},
"parameters": {"aspectRatio": "1:1", "quality": "1", "n": 1},
}
state = {"idempotency_key": str(uuid.uuid4()), "body": body,
"task_id": None, "status": "creating"}
save(state) # no API key here; write before POST
elif state["body"]["input"]["prompt"] != PROMPT:
sys.exit("The state file holds a different prompt. Move it aside to start a new job.")
if OUT.exists() and state.get("status") == "downloaded":
saved_sha = state.get("download_sha")
if not saved_sha or hashlib.sha256(OUT.read_bytes()).hexdigest() == saved_sha:
print("already saved", OUT)
return
if not state["task_id"]:
code, task = call("POST", "/media/tasks", state["body"],
{"Idempotency-Key": state["idempotency_key"]})
if code is None:
sys.exit(f"Create not confirmed: {task['error']}. Rerun to retry the same key and body.")
if code == 409:
sys.exit("409 idempotency_key_reused: same key, different body. Restore the saved body.")
if code == 503:
sys.exit("503 no_available_channel: check model access for this key/account; "
"contact support with the request id if it persists.")
if code not in (200, 202) or "id" not in task:
sys.exit(f"Create failed: HTTP {code} {task}")
state.update(task_id=task["id"], status=task["status"])
save(state)
deadline = time.monotonic() + 900
while True:
code, task = call("GET", f"/media/tasks/{state['task_id']}")
if code is None:
sys.exit(f"Polling stopped: {task['error']}. The job is still saved; rerun this script.")
if code != 200 or "status" not in task:
sys.exit(f"Poll failed: HTTP {code} {task}")
state["status"] = task["status"]
save(state)
if task["status"] in ("failed", "canceled"):
sys.exit(f"Job {task['status']}: {task.get('error')}")
if task["status"] == "succeeded":
break
if time.monotonic() > deadline:
sys.exit(f"Still {task['status']} after 900 s. Rerun with the same state file.")
time.sleep(min(8, 2 + task.get("progress", {}).get("percent", 0) // 20))
asset = task["assets"][0]
if asset.get("mime_type") != "image/png":
sys.exit(f"Expected a PNG grid, got {asset.get('mime_type')}")
try:
with urllib.request.urlopen(asset["url"], timeout=120) as response:
data = response.read() # signed URL: no Authorization header
except (urllib.error.HTTPError, urllib.error.URLError, TimeoutError) as error:
sys.exit(f"Download failed: {error}. Rerun to get a fresh signed URL and retry.")
digest = hashlib.sha256(data).hexdigest()
if asset.get("sha256") and digest != asset["sha256"]:
sys.exit("SHA-256 mismatch. Rerun to download the asset again.")
part = OUT.with_suffix(".part")
part.write_bytes(data)
part.replace(OUT)
state.update(status="downloaded", download_sha=digest)
save(state)
print("saved", OUT, len(data), "bytes")
if __name__ == "__main__":
main()
Bentuk permintaan dan respons berasal dari uji integrasi 12 November; status mulai ulang adalah tambahan di sini, dan cabang siklus hidupnya diperiksa offline dengan respons tiruan.
File status menyimpan yang Anda butuhkan untuk melanjutkan: body JSON dan UUID yang dipakai sebagai kunci idempotensi. File ini tidak menyimpan kunci API. File ditulis sebelum POST, jadi koneksi yang terputus meninggalkan kedua nilai di disk untuk pemulihan.
Panggilan pembuatan bisa mengembalikan dua kode sukses. 202 menerima tugas baru. 200 berarti OmniaKey sudah melihat kunci dan body yang sama dan mengembalikan tugas asli; lanjutkan memeriksa tugas itu. Kirim lagi body dan kunci yang sama hanya jika hasil pembuatan tidak diketahui setelah koneksi gagal. Dokumentasi mencantumkan 409 idempotency_key_reused untuk body yang berubah.
Kendalikan loop pemeriksaan dengan status. Persentase bersifat perkiraan dan bisa tetap 0 selama tugas berjalan. Berhenti pada succeeded, failed, atau canceled. Dokumentasi siklus hidup tugas media OmniaKey (diperiksa 12 November 2026) menjelaskan status tersebut.
Batas pemeriksaan bersifat lokal. Saat batas habis, tugas masih berjalan atau antre; menjalankan skrip yang sama lagi akan membaca id tersimpan dan melanjutkan pemeriksaan. Timeout lokal bukan pembatalan. Pembatalan memakai endpoint terpisah.
Grid gambar Midjourney yang dikembalikan
Tugas yang berhasil punya satu aset: grid PNG. Ini sampel dari uji integrasi 12 November 2026:

Respons di bawah dipersingkat: URL disamarkan dan expires_at adalah nilai historis. Respons ini menambahkan kolom aset yang Anda butuhkan:
{
"id": "task_DbCWJPfPL1jyhSD38IihNHiiFQao8hjV",
"status": "succeeded",
"progress": {"percent": 100, "stage": "completed"},
"assets": [
{
"kind": "image",
"mime_type": "image/png",
"width": 2048,
"height": 2048,
"byte_size": 5834301,
"sha256": "f503cef038d15fa150b36b5fe7c41874febad3aa1167698d790781e47a4a10b9",
"expires_at": "2026-11-12T04:16:41Z",
"url": "https://…redacted-signed-url…"
}
]
}
Baca width dan height dari aset, jangan menetapkan 2048 secara hard-code. Persegi 2048x2048 dan 197,1 detik adalah satu sampel; perlakukan seperti itu. Keempat kandidat berbagi satu PNG, jadi potong grid setelah diunduh jika aplikasi Anda butuh gambar terpisah.
url bertanda tangan dan berumur pendek, sekitar satu jam. Catatan tugas dan gambar disimpan 24 jam setelah pembuatan, menurut dokumentasi API gambar OmniaKey (diperiksa 12 November 2026). Unduh sebelum URL kedaluwarsa. Jika sudah kedaluwarsa, periksa id tugas lagi untuk mendapatkan URL bertanda tangan baru.
Unduh URL aset dengan GET biasa dan tanpa header Authorization. Tanda tangannya ada di URL. Skrip juga membandingkan byte yang diunduh dengan sha256 tugas, sehingga file terpotong terdeteksi sebelum menimpa salinan bagus Anda.
Menjalankan ulang setelah timeout atau unduhan gagal
Jalankan perintah yang sama dan pertahankan tugas. Skrip membaca midjourney-task.json dan memilih jalur aman terpendek:
- Pembuatan belum terkonfirmasi: skrip mengirim POST body yang sama dengan kunci idempotensi yang sama.
- Id tugas ada dan tugas masih berjalan: skrip memeriksa id yang ada.
- Tugas berhasil tetapi PNG hilang: skrip memeriksa sekali untuk URL bertanda tangan baru dan mengunduh lagi.
- PNG sudah tersimpan dan cocok dengan SHA-256 yang dicatat: skrip keluar tanpa permintaan lain. File rusak diperiksa dan diunduh lagi.
Ini berfungsi dalam jendela penyimpanan 24 jam. Kunci yang sama dengan prompt atau parameter berbeda menghasilkan 409. Skrip menolak file status yang prompt-nya tidak lagi cocok; pindahkan file jika Anda mengubah parameter.
Error dan perbaikan
Kegagalan berikut berasal dari aturan tugas dan idempotensi API. Perbaiki penyebabnya, lalu jalankan ulang dengan file status yang sama bila berlaku.
| Respons | Kode | Yang harus dilakukan |
|---|---|---|
| 400 | missing_idempotency_key | Tambahkan header; jaga di bawah 255 karakter |
| 409 | idempotency_key_reused | Kirim body asli atau mulai tugas baru dengan kunci baru |
| 503 | no_available_channel | Periksa akses untuk kunci/akun ini; hubungi dukungan jika berlanjut |
failed | error.code, error.message | Baca error tugas; tugas gagal dikembalikan dananya |
canceled | — | Tugas berhenti; buat yang baru jika masih perlu |
503 no_available_channel tidak berarti kunci tidak punya izin model. Dua pengiriman dengan satu kunci yang dipakai di kelompok ini mengembalikan 503 dan tidak membuat tugas; kunci lain berhasil dalam uji integrasi lebih awal pada hari yang sama. Penyebabnya tidak diketahui: bisa jadi ketersediaan kunci/akun atau ketersediaan kanal upstream. Pastikan midjourney tersedia untuk kunci/akun Anda saat ini. Jika 503 berlanjut, kirim body respons dan id permintaan ke dukungan.
200 saat pembuatan adalah tugas asli yang dikembalikan lagi. Hanya failed dan canceled yang merupakan kegagalan terminal; menghentikan skrip membiarkan tugas tetap berjalan.
Biaya dan kapan memakai API gambar lain
OmniaKey menagih sekali per tugas yang berhasil, dan tugas gagal atau dibatalkan dikembalikan dananya secara otomatis. Tarif saat ini ada di halaman model Midjourney; periksa sebelum memperkirakan satu kelompok.
Midjourney cocok untuk memilih di antara empat variasi dalam satu grid. Integrasi ini saat ini mengembalikan grid teks ke gambar tersebut; untuk satu gambar per panggilan atau edit yang mempertahankan adegan sumber, lihat GPT Image 2.5 API atau Nano Banana Pro API.
Jika Anda lebih suka mengetik prompt daripada menulis kode, AI Image Generator menjalankan model gambar di browser.
Pertanyaan umum
Apakah saya perlu langganan Midjourney untuk memakai API ini?
Tidak. Kunci berasal dari OmniaKey dan panggilan ditujukan ke API pihak ketiga OmniaKey. OmniaKey bukan Midjourney; langganan di situs Midjourney adalah produk lain dan tidak membuat kunci OmniaKey.
Mengapa satu tugas Midjourney mengembalikan empat gambar dalam satu file?
Midjourney mengembalikan grid 2x2 berisi empat kandidat sebagai satu PNG. Keempatnya berbagi file itu, dan upscale serta vary tidak tersedia di integrasi ini, jadi potong grid sendiri setelah mengunduh jika butuh file terpisah.
Apa arti 409 idempotency_key_reused?
Anda mengirim kunci idempotensi yang sudah dimiliki OmniaKey, tetapi body permintaan berubah. Kirim body asli atau mulai tugas baru dengan kunci baru. Memakai ulang kunci dengan prompt berbeda adalah penyebab umum.
Apa yang terjadi jika skrip saya timeout saat memeriksa status?
Tugas tetap berjalan. Id tugas ada di midjourney-task.json, jadi menjalankan skrip yang sama lagi akan memeriksa id itu atau mengunduh aset yang sudah selesai. Timeout lokal membiarkan tugas hidup dan biaya tetap berlaku.
Model di artikel ini
Artikel terkait
Nano Banana Pro API: tutorial Python, edit gambar, dan harga
Satu POST, satu polling, satu unduhan: skrip Nano Banana Pro yang langsung jalan.
GPT Image 2.5 API: membuat dan mengedit gambar dengan Python
Satu POST membuat tugas dan satu GET membaca hasilnya. Berikut kode permintaannya, ukuran yang kami jalankan pada 29 Oktober 2026, dan satu edit sebelum dan sesudah.
GPT Image 2.6: ulasan GIF, SVG, biaya, dan untuk siapa
Apa yang baru di GPT Image 2.6, diuji dengan GIF kami sendiri, tiga poster, dan satu edit foto.

