Cara Memanggil API Nano Banana Pro: Penelusuran Lengkap
Ini seluruh integrasinya, dari awal sampai akhir, untuk Nano Banana Pro di API E2X. Dapatkan sebuah key, kirim sebuah job, baca response-nya, tunggu dengan benar, tangani cara-cara ia bisa gagal, dan taruh byte-nya di tempat yang masih akan ada besok.
Langkah terakhir itulah yang menjerat orang. Lompat ke sana kalau Anda sudah menghasilkan gambar dan hanya ingin tahu kenapa gambar Anda hilang.

Apakah Pro tier yang benar untuk pekerjaan Anda adalah pertanyaan lain dan kami menjawabnya terpisah, di tulisan soal harga dan kecepatan. Versi singkatnya: $0.075 per request, sekitar 30 detik, sepadan kalau gambar Anda membawa teks yang terbaca atau menggabungkan referensi yang memainkan peran berbeda. Halaman ini mengandaikan Anda sudah memutuskan.
Yang Anda butuhkan sebelum request pertama
Empat hal, dan tiga di antaranya masing-masing satu baris.
- Sebuah API key. Buat satu dari akun E2X Anda. Semua di bawah ini mengirimnya sebagai
Authorization: Bearer $E2X_API_KEY. Simpan di sisi server. Key di dalam JavaScript browser adalah key yang sekarang dibelanjakan orang lain. - Base URL-nya, yaitu
https://api.e2x.ai/v1untuk setiap model di katalog. - Slug yang benar. Generasi adalah
google/nano-banana-pro/text-to-image. Penyuntingan adalahgoogle/nano-banana-pro/edit-image. String itu masuk ke body request apa adanya, dan tidak ada pencocokan kabur atasnya. - Prompt yang layak dikirim. Pro mengganjar kekhususan lebih besar daripada tier flash, karena ia punya lebih banyak ruang untuk menjalankannya. Kami punya panduan prompting terpisah kalau Anda mau masuk lebih dalam daripada "seekor kucing, tapi sinematik".
Kontraknya asinkron. Anda mengirim sebuah job, Anda mendapat sebuah ID, dan gambarnya tiba belakangan. Tidak ada endpoint sinkron yang memblokir sampai pikselnya siap, dan mengingat Pro butuh sekitar 30 detik, Anda pun tidak akan menginginkannya.
Request text-to-image pertama Anda
curl -X POST https://api.e2x.ai/v1/jobs/submit \
-H "Authorization: Bearer $E2X_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "google/nano-banana-pro/text-to-image",
"input": {
"prompt": "Papan menu tulis tangan dengan kapur di belakang konter kopi marmer, cahaya sore hangat dari jendela di sebelah kiri, depth of field dangkal",
"aspect_ratio": "16:9",
"resolution": "2k"
}
}'
Hal yang sama dalam Python:
import os
import requests
BASE = "https://api.e2x.ai/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['E2X_API_KEY']}"}
def submit(prompt, aspect_ratio="16:9", resolution="2k"):
r = requests.post(
f"{BASE}/jobs/submit",
headers=HEADERS,
json={
"model": "google/nano-banana-pro/text-to-image",
"input": {
"prompt": prompt,
"aspect_ratio": aspect_ratio,
"resolution": resolution,
},
},
timeout=30,
)
r.raise_for_status()
return r.json()["data"]["jobId"]
Kedua contohnya memaku aspect_ratio dan resolution dengan sengaja, dan kedua default-nya layak dipahami sebelum Anda membuangnya.
aspect_ratio default ke 9:16. Bukan 1:1. Kalau Anda meninggalkannya, setiap gambar yang Anda hasilkan berbentuk potret, selamanya, dan Anda tidak akan menyadarinya sampai sebuah slot lebar di tata letak Anda terlihat keliru. Field ini menjegal lebih banyak integrasi daripada field lain mana pun di API kami. Paku nilainya.
Nilai resolution adalah huruf kecil. 1k, 2k, 4k. 2K huruf besar bukan string yang sama dan API akan memberi tahu Anda demikian.
Perlakukan 1k sebagai nilai mati di slug ini. Dua pengaturan pertamanya duduk di satu tagihan datar — $0.075 untuk keduanya, diperiksa 26 Agustus 2026 — jadi yang lebih kecil sekadar mengembalikan lebih sedikit piksel untuk baris faktur yang sama. Hanya 4k yang menggerakkan angkanya: $0.15, plafon 4096×4096.

Apa yang kembali
Call submit langsung mengembalikan sebuah amplop job. Field yang Anda butuhkan adalah data.jobId:
{
"success": true,
"data": {
"jobId": "job_8Kd2mQvXpL",
"status": "pending"
}
}
Status bergerak pending → processing → completed, atau mendarat di salah satu dari dua kegagalan terminal, failed dan cancelled. Job yang selesai membawa hasilnya di data.outputs[0].url, dan yang gagal membawa alasannya di data.error.message.
Satu detail untuk diresapi sebelum Anda menulis kode penagihan apa pun: setiap nilai moneter yang dikembalikan API berada dalam mikro-sen. Satu juta sama dengan satu dolar. Sebuah request Nano Banana Pro karena itu kembali sebagai 75000, bukan 0.075. Bagi dengan 1.000.000 di lapisan tampilan dan tidak di tempat lain, dan jangan pernah menyimpan angka hasil pembagiannya.
Polling tanpa menggedor
Versi kasarnya berhasil:
curl https://api.e2x.ai/v1/jobs/job_8Kd2mQvXpL \
-H "Authorization: Bearer $E2X_API_KEY"
Bungkus itu dalam sebuah loop dengan sleep tetap dua detik dan Anda punya integrasi yang berfungsi. Khusus untuk Nano Banana Pro, interval tetap memang bisa diterima — sebuah request berjalan sekitar 30 detik, jadi Anda melakukan kira-kira lima belas call status lalu berhenti. Itu bukan trafik yang cukup untuk mengganggu siapa pun.
Backoff tetap lebih baik, karena satu alasan yang tidak ada hubungannya dengan kesopanan. Interval tetap menyembunyikan variansi. Kalau sebuah job butuh 90 detik alih-alih 30, loop tetap terus memanggil pada laju yang sama dan log Anda terlihat identik dengan eksekusi yang sehat. Backoff yang tumbuh membuat job yang lambat terlihat lambat.
import time
TERMINAL = {"completed", "failed", "cancelled"}
def wait_for(job_id, timeout=300):
delay = 2.0
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
r = requests.get(f"{BASE}/jobs/{job_id}", headers=HEADERS, timeout=30)
r.raise_for_status()
data = r.json()["data"]
if data["status"] in TERMINAL:
return data
time.sleep(delay)
delay = min(delay * 1.4, 10.0)
raise TimeoutError(f"{job_id} still running after {timeout}s")
Dua hal yang dilakukan loop itu yang biasanya tidak dilakukan loop naif. Ia punya tenggat keras, jadi job yang macet melempar error alih-alih berputar sampai prosesnya dibunuh. Dan ia memperlakukan ketiga keadaan terminalnya dengan cara yang sama di lapisan transport, mengembalikan payload-nya dan membiarkan pemanggilnya memutuskan apa arti sebuah kegagalan. Logika retry adalah milik lapisan di atas fungsi ini, bukan di dalamnya.

Webhook, dan kenapa sebaiknya Anda pindah ke sana
Oper webhookUrl di dalam body submit dan kami memanggil Anda ketika job-nya mencapai keadaan terminal. Sama sekali tanpa loop polling.
curl -X POST https://api.e2x.ai/v1/jobs/submit \
-H "Authorization: Bearer $E2X_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "google/nano-banana-pro/text-to-image",
"input": {
"prompt": "Maket arsitektur sebuah jembatan penyeberangan di atas meja gambar, cahaya utara",
"aspect_ratio": "3:2",
"resolution": "2k"
},
"webhookUrl": "https://your-app.example.com/hooks/e2x"
}'
Polling adalah langkah pertama yang benar karena Anda bisa mengujinya dari terminal dalam sepuluh detik. Ia keadaan tetap yang keliru, dan alasannya aritmetika. Satu gambar pada satu waktu, polling menghabiskan satu loop. Dua ratus gambar dalam satu batch dan polling menghabiskan dua ratus loop bersamaan, masing-masing memegang sebuah koneksi selama setengah menit, di dalam proses yang sekarang tidak bisa di-restart tanpa kehilangan jejak setiap job yang sedang terbang.
Webhook membuat pekerjaannya bisa dimulai ulang. Job ID-nya masuk ke database Anda saat Anda mengirim, handler-nya memperbarui barisnya ketika kami memanggil, dan sebuah deploy di tengah-tengah tidak mengubah apa pun. Kalau Anda membangun pipeline generasi alih-alih sebuah script, inilah versi yang harus dibangun, dan ia berpasangan dengan pola-pola di tulisan kami soal mengotomatiskan generasi gambar dari ujung ke ujung.
Dua catatan operasional. Endpoint Anda harus bisa dijangkau dari internet publik, jadi URL localhost diam-diam tidak akan pernah menyala selama pengembangan — pakai tunnel. Dan perlakukan webhook-nya sebagai notifikasi, bukan sebagai sumber kebenaran: ambil job-nya berdasarkan ID di dalam handler sebelum Anda bertindak atasnya.
Menyunting gambar alih-alih menghasilkannya
Amplop yang sama, slug yang berbeda, satu field tambahan. Endpoint edit menerima image_urls di samping prompt dan berbiaya $0.075 yang sama.
curl -X POST https://api.e2x.ai/v1/jobs/submit \
-H "Authorization: Bearer $E2X_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "google/nano-banana-pro/edit-image",
"input": {
"prompt": "Ganti latarnya dengan sweep studio abu-abu lembut, pertahankan pencahayaan produknya persis seperti apa adanya",
"image_urls": ["https://your-cdn.example.com/source/bottle.jpg"],
"aspect_ratio": "1:1",
"resolution": "2k"
}
}'
URL yang Anda oper harus bisa diambil secara publik. URL bertanda tangan dari penyimpanan Anda sendiri berhasil; sebuah path di laptop Anda tidak.
Nano Banana Pro menerima sampai empat belas gambar referensi, dan tidak seperti tier lain ia memisahkannya berdasarkan peran — sampai 5 untuk identitas karakter, sampai 6 untuk kesetiaan objek, sampai 3 untuk gaya. Pembagian peran itulah alasan berada di tier ini sama sekali, dan nama field persis untuk referensi bercakupan peran didokumentasikan per model di file spesifikasi yang bisa dibaca mesin, yang menjadi otoritas kalau dokumentasi kami dan tulisan ini suatu saat berbeda. Khusus untuk alur kerja konsistensi karakter, kami masuk lebih dalam di panduan generasi yang konsisten.
Setiap parameter, dan default-nya
| Field | Letaknya | Nilai yang diterima | Default |
|---|---|---|---|
model | akar body | google/nano-banana-pro/text-to-image atau google/nano-banana-pro/edit-image | wajib |
input.prompt | di dalam input | string | wajib |
input.aspect_ratio | di dalam input | 9:16, 16:9, 1:1, 2:3, 3:2, 21:9, 3:4, 4:3, 4:5, 5:4 | 9:16 |
input.resolution | di dalam input | 1k, 2k, 4k | paku secara eksplisit |
input.image_urls | di dalam input, hanya slug edit | array URL yang bisa dijangkau publik | wajib pada edit |
webhookUrl | akar body | sebuah endpoint HTTPS publik | tidak ada, lakukan polling |
Dua baris yang merugikan orang secara finansial adalah aspect_ratio dan resolution. Semua yang lain berperilaku seperti dugaan Anda.
Ketika job-nya tidak selesai
Tiga permukaan kegagalan, dan semuanya butuh penanganan yang berbeda.
Call submit-nya sendiri gagal. Ini error HTTP sebelum job apa pun ada — key yang salah, body yang cacat bentuk, slug model yang tak dikenal. Tidak ada yang diantrekan dan tidak ada yang ditagih. Perbaiki request-nya; mengulanginya tanpa perubahan akan gagal secara identik.
Job-nya mencapai failed. Job-nya ada dan modelnya tidak memproduksi sebuah gambar. Baca data.error.message untuk alasannya, yang biasanya berupa penolakan kebijakan konten atau input yang cacat bentuk seperti URL yang tak terjangkau di image_urls. Retry buta atas penolakan kebijakan gagal dengan cara yang sama; retry setelah error upstream yang sesaat biasanya berhasil. Catat pesannya, jangan hanya mencatat statusnya.
Job-nya mencapai cancelled. Terminal, dan bukan bug. Perlakukan persis seperti failed di tingkat kode — barisnya tertutup, tidak ada output yang akan datang.
Loop tunggu Anda kehabisan waktu. Ini bukan keadaan job. Artinya job-nya masih berjalan dan kesabaran Anda habis. Job ID-nya masih sah, jadi catat dan periksa lagi belakangan alih-alih mengirim ulang, yang akan menagih Anda dua kali untuk gambar yang sama.
def generate(prompt, **kw):
job_id = submit(prompt, **kw)
job = wait_for(job_id)
if job["status"] != "completed":
reason = (job.get("error") or {}).get("message", "no reason given")
raise RuntimeError(f"{job_id} ended as {job['status']}: {reason}")
return job["outputs"][0]["url"]
Unduh output-nya sebelum ia kedaluwarsa
Inilah bagian yang merilis gambar rusak seminggu setelah peluncuran, jadi ia mendapat bagiannya sendiri.
URL di data.outputs[0].url bersifat sementara. Ia URL pengiriman, bukan hosting. Kalau Anda menulis string itu ke sebuah kolom database bernama image_url dan merendernya di halaman produk, halamannya berfungsi di staging, berfungsi saat tinjauan, berfungsi di hari peluncuran, lalu diam-diam berubah menjadi ikon gambar rusak begitu objeknya melewati usianya.
Obatnya satu langkah dan ia tidak opsional. Ambil byte-nya, taruh di penyimpanan Anda sendiri, simpan URL Anda.
import pathlib
def download(url, dest):
with requests.get(url, stream=True, timeout=120) as r:
r.raise_for_status()
pathlib.Path(dest).parent.mkdir(parents=True, exist_ok=True)
with open(dest, "wb") as f:
for chunk in r.iter_content(chunk_size=1 << 16):
f.write(chunk)
return dest
Atau, dari shell:
curl -sL "$OUTPUT_URL" -o ./out/menu-board.jpg
Lakukan unduhannya di dalam unit kerja yang sama yang menangani penyelesaiannya. Bukan di sebuah cron satu jam kemudian, bukan secara malas pada tampilan halaman pertama. Jendelanya cukup longgar sehingga Anda akan lolos dengan penundaan saat pengujian dan cukup sempit sehingga Anda tidak akan lolos di bawah beban.

Semuanya, sebagai satu script
Semua di atas, dirakit. Setel E2X_API_KEY dan jalankan.
#!/usr/bin/env python3
"""Hasilkan satu gambar dengan Nano Banana Pro dan simpan secara lokal."""
import os
import pathlib
import time
import requests
BASE = "https://api.e2x.ai/v1"
MODEL = "google/nano-banana-pro/text-to-image"
HEADERS = {"Authorization": f"Bearer {os.environ['E2X_API_KEY']}"}
TERMINAL = {"completed", "failed", "cancelled"}
def submit(prompt, aspect_ratio="16:9", resolution="2k"):
r = requests.post(
f"{BASE}/jobs/submit",
headers=HEADERS,
json={
"model": MODEL,
"input": {
"prompt": prompt,
"aspect_ratio": aspect_ratio,
"resolution": resolution,
},
},
timeout=30,
)
r.raise_for_status()
return r.json()["data"]["jobId"]
def wait_for(job_id, timeout=300):
delay = 2.0
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
r = requests.get(f"{BASE}/jobs/{job_id}", headers=HEADERS, timeout=30)
r.raise_for_status()
data = r.json()["data"]
if data["status"] in TERMINAL:
return data
time.sleep(delay)
delay = min(delay * 1.4, 10.0)
raise TimeoutError(f"{job_id} still running after {timeout}s")
def download(url, dest):
with requests.get(url, stream=True, timeout=120) as r:
r.raise_for_status()
pathlib.Path(dest).parent.mkdir(parents=True, exist_ok=True)
with open(dest, "wb") as f:
for chunk in r.iter_content(chunk_size=1 << 16):
f.write(chunk)
return dest
def main():
job_id = submit(
"Papan menu tulis tangan dengan kapur di belakang konter kopi marmer, "
"cahaya sore hangat dari jendela di sebelah kiri, depth of field dangkal"
)
print("submitted", job_id)
job = wait_for(job_id)
if job["status"] != "completed":
reason = (job.get("error") or {}).get("message", "no reason given")
raise SystemExit(f"{job_id} ended as {job['status']}: {reason}")
path = download(job["outputs"][0]["url"], "out/menu-board.jpg")
print("saved", path)
if __name__ == "__main__":
main()
Tukar slug-nya dengan google/nano-banana-pro/edit-image dan tambahkan image_urls dan script yang sama menyunting alih-alih menghasilkan. Tukar dengan Nano Banana 2 atau Nano Banana 2 Lite dan ia tetap berjalan, karena amplopnya identik di semua yang ada di kategori text-to-image dan semua yang ada di image-to-image. Hanya field input-nya yang berbeda, dan tulisan perbandingan model membahas mana yang jadi sasarannya.
Satu hal terakhir yang bukan kode. Setiap gambar dari setiap model Google membawa watermark SynthID dan tidak ada provider yang bisa menonaktifkannya. Selesaikan itu dengan siapa pun yang menandatangani kontraknya sebelum Anda membangun di atasnya.
Pertanyaan yang sering diajukan
Bagaimana cara memanggil API Nano Banana Pro?
Kirim POST ke https://api.e2x.ai/v1/jobs/submit dengan bearer token, slug model google/nano-banana-pro/text-to-image, dan sebuah objek input yang memuat prompt Anda. Response-nya mengembalikan data.jobId. Lakukan polling terhadap https://api.e2x.ai/v1/jobs/{id} atau oper sebuah webhookUrl di body submit, lalu baca gambar jadinya dari data.outputs[0].url.
Apa default aspect ratio untuk Nano Banana Pro?
9:16, yang berarti potret. Ini mengejutkan hampir semua orang, karena kebanyakan API gambar default ke kotak. Kalau Anda tidak menyetel aspect_ratio secara eksplisit, setiap gambar keluar vertikal. Modelnya menerima 9:16, 16:9, 1:1, 2:3, 3:2, 21:9, 3:4, 4:3, 4:5 dan 5:4.
Kenapa URL gambar Nano Banana Pro saya rusak?
Karena URL output yang kami kembalikan adalah pengiriman sementara, bukan hosting permanen. Pipeline mana pun yang menyimpan URL kami ke sebuah database dan merendernya kemudian akan menampilkan gambar rusak begitu objeknya kedaluwarsa. Unduh byte-nya di langkah yang sama yang menangani penyelesaian job-nya dan simpan di bucket Anda sendiri.
Sebaiknya saya memakai polling atau webhook dengan API E2X?
Lakukan polling selagi Anda membangun, karena Anda bisa mengujinya dari terminal. Pindah ke webhook untuk apa pun yang berjalan di produksi. Sebuah job Nano Banana Pro butuh sekitar 30 detik, jadi satu batch berisi dua ratus berarti dua ratus loop polling bersamaan yang semuanya kehilangan state-nya pada deploy berikutnya. Dengan webhookUrl, job ID-nya masuk ke database Anda pada saat submit dan handler-nya mengambilnya belakangan.
Bagaimana cara menyunting gambar yang sudah ada dengan Nano Banana Pro?
Pakai slug google/nano-banana-pro/edit-image dan tambahkan array image_urls ke objek input di samping prompt Anda. URL-nya harus bisa diambil secara publik, jadi URL bertanda tangan dari penyimpanan Anda berhasil sedangkan path lokal tidak. Menyunting berbiaya $0.075 yang sama dengan menghasilkan.
Resolusi apa yang sebaiknya saya minta dari Nano Banana Pro?
Kirim 2k. Dua pengaturan pertamanya berbagi satu tagihan datar di slug ini, jadi 1k benar-benar kalah telak — lebih sedikit piksel, baris faktur yang identik. Raih 4k hanya ketika Anda sungguh butuh plafon 4096×4096, karena ia melipatgandakan tagihannya menjadi $0.15. Ketiga nilainya huruf kecil.
Kenapa API E2X mengembalikan harga seperti 75000?
Setiap nilai moneter di API dinyatakan dalam mikro-sen, di mana 1.000.000 sama dengan satu dolar AS. Sebuah 75000 pada job Nano Banana Pro berarti $0.075. Simpan bilangan bulatnya di penyimpanan dan bagi hanya pada titik seorang manusia membacanya, sehingga pembulatan tidak pernah menumpuk sepanjang satu periode penagihan.