Kembali ke Blog

Cara Memanggil API Nano Banana Pro: Penelusuran Lengkap

E2X Team··13 menit membaca
nano-banana-proapi-tutorialimage-generationwebhooksgoogle

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.

Rumah instrumen presisi milik seorang masinis dari baja anodisasi gelap dengan muka dial kosong tanpa tanda dan kenop penyetel bergerigi, disinari rim light sian dingin di latar arang

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/v1 untuk setiap model di katalog.
  • Slug yang benar. Generasi adalah google/nano-banana-pro/text-to-image. Penyuntingan adalah google/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.

Makro ekstrem sebuah kenop penyetel baja bergerigi yang terpasang di rumah instrumen arang doff, satu highlight dingin yang sempit di sepanjang alur bubutannya

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.

Roda escapement baja yang dipoles dan garpu palet di dalam instrumen presisi yang terbuka, depth of field sangat dangkal, cahaya biru keabuan yang dingin di atas arang

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

FieldLetaknyaNilai yang diterimaDefault
modelakar bodygoogle/nano-banana-pro/text-to-image atau google/nano-banana-pro/edit-imagewajib
input.promptdi dalam inputstringwajib
input.aspect_ratiodi dalam input9:16, 16:9, 1:1, 2:3, 3:2, 21:9, 3:4, 4:3, 4:5, 5:49:16
input.resolutiondi dalam input1k, 2k, 4kpaku secara eksplisit
input.image_urlsdi dalam input, hanya slug editarray URL yang bisa dijangkau publikwajib pada edit
webhookUrlakar bodysebuah endpoint HTTPS publiktidak 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.

Kotak spesimen aluminium bubut yang terbuka dilapisi potongan busa abu-abu gelap, satu di antaranya memegang cakram baja yang dipoles sementara potongan di sebelahnya kosong

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.