Cara Menghasilkan Gambar Otomatis: Template, Job dan Webhook
Kebanyakan jawaban atas pertanyaan ini berupa tangkapan layar sebuah kotak teks. Ketik prompt, tekan tombol, tunggu, unduh, ulangi. Itu bukan otomasi. Itu Anda, bekerja dengan tangan, lebih cepat.
Otomatis berarti tidak ada manusia di dalam putarannya. Sebaris data tiba, sebuah gambar keluar, tidak ada yang menyaksikannya terjadi. Itu butuh empat bagian: template prompt yang berlubang, data untuk mengisi lubangnya, antrean yang menerima pekerjaan tanpa memblokir, dan tempat yang tahan lama untuk menaruh hasilnya. Kami menjalankan API di tengah semua itu, jadi kami melihat pipeline yang orang bangun sekaligus yang diam-diam patah tiga minggu setelah diluncurkan.

Bagian yang tidak dikatakan siapa pun lebih dulu: sekarang ini murah
Mulailah dengan angkanya, karena ia mengubah apa yang bersedia Anda bangun.
Seribu gambar lewat Nano Banana 2 Lite berbiaya $23.80. Itu 1.000 × $0.0238, pada harga kami tanggal 26 Agustus 2026. Seratus ribu foto produk — sebuah katalog sungguhan, setiap SKU, setiap varian warna — adalah $2,380.
Volume yang sama di seluruh tier yang mungkin Anda pilih:
| Gambar | Nano Banana 2 Lite | Nano Banana 2 | Nano Banana Pro |
|---|---|---|---|
| 100 | $2.38 | $4.00 | $7.50 |
| 1.000 | $23.80 | $40.00 | $75.00 |
| 10.000 | $238.00 | $400.00 | $750.00 |
| 100.000 | $2,380.00 | $4,000.00 | $7,500.00 |
Harga dan ketentuan produk dapat berubah sewaktu-waktu. Periksa harga terkini masing-masing provider sebelum mengambil keputusan pembelian. Harga Google Batch atau Flex tidak setara langsung dengan request API on-demand standar karena kondisi penjadwalan, ketersediaan, dan pemrosesannya berbeda; karena itu harga tersebut tidak disertakan dalam perbandingan ini. Ini adalah perbandingan dengan cakupan terbatas, bukan klaim bahwa E2X adalah opsi termurah di dunia dalam setiap konfigurasi.
Kebanyakan orang yang bertanya bagaimana mengotomatiskan generasi gambar diam-diam sudah memberi harganya label "terlalu mahal untuk dicoba". Ini pertanyaan senilai $23.80. Bangun saja.
Langkah 1: berhenti menulis prompt, mulailah menulis template
Prompt yang Anda ketik sekali adalah sebuah kalimat. Prompt yang dijalankan mesin sepuluh ribu kali adalah template dengan slot, dan perbedaan itulah seluruh pekerjaannya.
Aturannya: semua yang bervariasi masuk ke slot, semua yang harus tetap identik masuk ke teks yang dipatok. Salah menaruh batas itu dan set-nya melenceng — separuh gambar di atas putih, separuh di atas abu-abu, karena "latar" bocor ke bagian variabel.
TEMPLATE = (
"Foto produk studio sebuah {product_name} berwarna {colour}, "
"di tengah latar abu-abu hangat polos, key light terarah yang lembut "
"dari kiri atas, depth of field dangkal, gaya katalog editorial, "
"tanpa teks, tanpa logo, tanpa orang"
)
Dua slot. Pencahayaan, latar, framing dan pengecualiannya dibekukan. Separuh yang beku itulah yang membuat 400 gambar tampak seperti satu sesi pemotretan alih-alih 400 kecelakaan.
Jauhkan empat hal dari separuh yang variabel: medium, arah cahaya, latar, dan instruksi negatifnya. Itu identitas visual Anda. Kalau semuanya bergerak per baris, Anda tidak punya identitas.

Kerajinan prompt itu sendiri adalah tulisan terpisah. Yang penting untuk otomasi adalah bentuknya: rangka yang tetap, lubang yang bernama, tanpa kejutan.
Langkah 2: datanya adalah produk yang sebenarnya
Template-nya sepele. Datanya tempat pekerjaan itu berada, dan biasanya ia sesuatu yang sudah Anda miliki.
- Tabel katalog produk. Satu baris per SKU, kolom untuk nama, warna, material, kategori.
- Ekspor CMS berisi tulisan blog, di mana judul dan topik menjadi slot untuk gambar header per artikel.
- Baris-baris di database aplikasi Anda — listing buatan pengguna, halaman acara, resep.
- Spreadsheet berisi varian iklan: enam headline dikali empat latar adalah dua puluh empat gambar, dan tak seorang pun membuat brief-nya dengan tangan.
Normalkan sumber apa pun itu menjadi daftar dictionary sebelum ia menyentuh API, dan pertahankan ID yang stabil di setiap baris. Anda membutuhkannya untuk mencocokkan hasil kembali ke record, dan melewatinya terasa sakit persis pada saat sebuah webhook menyala.
Langkah 3: kirim, jangan menunggu
API kami asinkron dengan sengaja. Anda POST sebuah job, Anda langsung mendapat job ID kembali, dan generasinya terjadi di sisi kami.
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-2-lite/text-to-image",
"input": {
"prompt": "Foto produk studio sebuah lampu meja kayu walnut berwarna hitam doff...",
"aspect_ratio": "1:1"
},
"webhookUrl": "https://your-app.example.com/hooks/e2x"
}'
Walker yang mengubah sebuah tabel menjadi job panjangnya sekitar tiga puluh baris. Ia membaca CSV, memformat template per baris, mengirim, dan mencatat job ID terhadap ID barisnya sehingga tidak ada yang menjadi yatim.
import csv
import os
import time
import requests
API = "https://api.e2x.ai/v1"
HEADERS = {
"Authorization": f"Bearer {os.environ['E2X_API_KEY']}",
"Content-Type": "application/json",
}
TEMPLATE = (
"Foto produk studio sebuah {product_name} berwarna {colour}, "
"di tengah latar abu-abu hangat polos, key light terarah yang lembut "
"dari kiri atas, depth of field dangkal, gaya katalog editorial, "
"tanpa teks, tanpa logo, tanpa orang"
)
MAX_IMAGES = 500 # plafon keras, lihat bagian biaya
UNIT_COST = 0.0238 # Nano Banana 2 Lite, diperiksa 26 Agustus 2026
def submit(row):
body = {
"model": "google/nano-banana-2-lite/text-to-image",
"input": {
"prompt": TEMPLATE.format(**row),
"aspect_ratio": "1:1",
},
"webhookUrl": "https://your-app.example.com/hooks/e2x",
}
for attempt in range(4):
r = requests.post(f"{API}/jobs/submit", json=body, headers=HEADERS, timeout=30)
if r.status_code < 300:
return r.json()["data"]["jobId"]
if r.status_code == 429 or r.status_code >= 500:
time.sleep(2 ** attempt)
continue
raise RuntimeError(f"row {row['id']} rejected: {r.status_code} {r.text}")
raise RuntimeError(f"row {row['id']} still failing after 4 attempts")
with open("catalog.csv") as fh:
rows = list(csv.DictReader(fh))[:MAX_IMAGES]
print(f"submitting {len(rows)} jobs, budget ${len(rows) * UNIT_COST:.2f}")
submitted = {}
for row in rows:
try:
submitted[row["id"]] = submit(row)
except RuntimeError as err:
print(f"skipped: {err}")
print(f"{len(submitted)}/{len(rows)} accepted")
Perhatikan apa yang tidak dilakukan loop itu: berhenti ketika satu baris gagal. Sebuah batch berisi 500 di mana baris ke-212 punya kolom warna kosong seharusnya memberi Anda 499 gambar dan satu skip yang tercatat, bukan stack trace pada pukul tiga pagi dan nol gambar.
Slug-nya lebih penting daripada tampaknya. google/nano-banana-2-lite/text-to-image membawa akhiran capability; slug teks Nano Banana 2 adalah google/nano-banana-2 telanjang tanpa akhiran apa pun. Menebak berbiaya 404 di sebuah pipeline yang selebihnya terlihat sudah rampung. Setiap model mempublikasikan daftar parameternya di sebuah file spesifikasi yang bisa dibaca mesin.
Langkah 4: webhook di atas polling, dan ini alasannya
Anda bisa melakukan polling. GET /v1/jobs/{JOB_ID} mengembalikan pending, processing, completed, failed atau cancelled, dan untuk script sekali pakai itu tidak masalah.
Untuk sebuah pipeline itu pilihan yang keliru, dan alasannya bukan keanggunan. Polling mengikat masa hidup proses Anda ke job paling lambat di dalam batch. Sebuah generasi Lite berjalan sekitar 60 detik di sisi kami. Kirim 500 dan poller-nya harus tetap hidup, memegang state, selama ekornya berlangsung — melewati sebuah deploy, restart container, timeout 15 menit di platform serverless mana pun yang Anda pakai. Ketika ia mati, ia mati sambil memegang satu-satunya catatan tentang job mana yang sedang terbang.
Sebuah webhook membalik itu. Anda mengirim lalu keluar. Belakangan, sebuah POST tiba membawa job yang selesai dan Anda menangani persis satu job itu, tanpa state.
// Handler Express. Idempoten: jobId yang sama bisa tiba dua kali.
app.post("/hooks/e2x", express.json(), async (req, res) => {
res.status(200).end(); // akui dulu, kerjakan setelahnya
const job = req.body.data;
if (job.status !== "completed") {
await markFailed(job.jobId, job.error?.message ?? "unknown");
return;
}
const already = await findAsset(job.jobId);
if (already) return;
await storeImage(job.jobId, job.outputs[0].url);
});
Lakukan polling ketika Anda menjalankan sebuah script dengan tangan dan menontonnya. Ambil webhook ketika tidak ada yang menonton, dan itulah definisi otomasi.
Langkah 5: URL output-nya sementara, dan begini pipeline patah
Ini dia. Kalau Anda membaca sekilas semua yang lain, baca bagian ini dua kali.
data.outputs[0].url adalah URL pengiriman, bukan penyimpanan. Ia bekerja sekarang. Ia tidak akan bekerja selamanya. Apa pun yang memperlakukannya sebagai permanen — sebuah kolom product_image_url, sebuah field CMS, sebuah tautan yang diemailkan ke klien — tampil baik-baik saja di staging dan menampilkan ikon gambar rusak dua minggu kemudian.
Kegagalannya jahat karena ia tertunda. Tidak ada yang error saat penulisan. Test lolos. Batch-nya melaporkan 500 keberhasilan. Lalu gambar mulai lenyap dari record yang paling tua lebih dulu, dan pada saat ada yang menyadarinya Anda tidak bisa meregenerasinya tanpa menjalankan ulang seluruh job, karena prompt-nya juga tidak pernah disimpan.
Unduh byte-nya. Taruh di bucket Anda sendiri. Simpan URL Anda sendiri.

import requests
import boto3
s3 = boto3.client("s3")
def store_image(job_id, row_id, source_url):
img = requests.get(source_url, timeout=60)
img.raise_for_status()
key = f"products/{row_id}.jpg"
s3.put_object(
Bucket="my-assets",
Key=key,
Body=img.content,
ContentType=img.headers.get("content-type", "image/jpeg"),
)
return f"https://cdn.example.com/{key}"
Selagi Anda ada di sana, simpan prompt-nya berdampingan dengan gambarnya. Satu kolom teks, dan itulah beda antara "regenerasi varian itu" dan "mulai dari awal".
Dua kebiasaan lagi yang layak dimiliki sejak hari pertama. Periksa bahwa unduhannya mengembalikan byte gambar dan bukan halaman error, karena sebuah 200 berisi HTML akan dengan senang hati tertulis ke bucket Anda. Dan kunci penyimpanannya pada ID baris Anda, bukan job ID kami, sehingga sebuah regenerasi menimpa objek yang benar alih-alih menelantarkannya.
Langkah 6: apa yang benar-benar salah pada volume besar
Batch kecil menyembunyikan segalanya. Inilah yang muncul begitu Anda melewati beberapa ratus.
Batch yang sebagian gagal itu normal. Sebagian dari setiap eksekusi besar akan gagal — sebuah prompt yang menyandung filter konten, baris yang cacat bentuk, error upstream yang sesaat. Perlakukan 497 dari 500 sebagai kasus sukses, dan beri diri Anda retry satu perintah atas tiga baris itu saja.
Retry butuh plafon pengeluaran. Loop retry tanpa batas adalah bug yang menagih. $0.0238 sekali tembak terdengar tidak berbahaya sampai sebuah loop yang macet menjalankannya empat puluh ribu kali. Taruh hitungan keras di dalam kode — baris MAX_IMAGES di atas adalah asuransi termurah di sini.
Idempotensi bukan opsional. Webhook bisa dikirimkan lebih dari sekali. Handler yang tidak aman dijalankan dua kali pada satu job ID memberi Anda aset ganda dan baris ganda, dan Anda menemukannya pada minggu tersibuk.
Biaya butuh penghitung yang hidup, bukan tagihan bulanan. Nilai moneter di API kami kembali dalam mikro-sen — 1.000.000 sama dengan $1. Jumlahkan per batch dan catat totalnya saat batch itu ditutup. Pipeline yang melaporkan "412 gambar, $9.81" setiap malam adalah pipeline yang tidak perlu diaudit siapa pun.
Default aspect ratio akan mengejutkan Anda. Lite default ke 1:1, sedangkan Nano Banana 2 dan Pro default ke 9:16. Patok nilainya di template atau separuh katalog Anda diam-diam menjadi potret.
Watermark-nya ikut bersama file-nya. Google mencap SynthID ke dalam semua yang dihasilkan model gambarnya. Ia tak kasatmata, ia bukan sebuah flag, dan ia bertahan apa pun yang dilakukan pipeline Anda terhadap byte-nya setelah itu. Siapa pun yang memegang urusan merek atau legal di pihak Anda sebaiknya menyetujui aset hasil AI sebelum pipeline-nya ada, bukan setelah ia menulis 20.000 objek ke dalam sebuah bucket.

Model mana yang jadi sasaran pipeline
Default-kan ke Nano Banana 2 Lite dan pindah darinya hanya ketika ada sesuatu yang spesifik memaksa Anda.
Itu aritmetika, bukan hedging. Pada $0.0238 ia hal termurah yang kami jual yang membuat sebuah gambar, satu generasi penuh lebih baru daripada Nano Banana asli yang digantikannya, dan pada volume pipeline jarak harganya berlipat menjadi satu-satunya angka yang dilihat bagian keuangan. Ia juga membawa empat aspect ratio yang tidak dipunyai apa pun yang lain — 1:4, 4:1, 1:8 dan 8:1 — persis yang Anda mau kalau output-nya banner dan rail vertikal. Satu keanehan: sama sekali tidak ada parameter resolution, dan mengirimnya adalah error, bukan no-op yang diam.
Berbeloklah menjauh darinya pada empat kasus ini, dan tidak selain itu:
- Output di atas 1K. Lite hanya 1K. Nano Banana 2 mencapai 4K pada dasar $0.04, dengan 2K di ×1,5 dan 4K di ×2.
- Teks yang terbaca di dalam gambar. Kartu produk berisi harga, infografis yang dilokalkan. Itu tinggal di Nano Banana Pro pada $0.075, di mana 1K dan 2K berbiaya sama — ambil yang 2K, ia gratis.
- Latar transparan. Potongan dan lembar stiker butuh
background: transparent, dan GPT Image 2 adalah satu-satunya model yang kami bawa yang melakukannya dalam satu call. Anggarkan $0.0525 pada 1K, bukan angka katalog mentahnya —qualitymengalikan dengan 7 di setiap tier. - Wajah yang sama atau botol yang sama di banyak frame. Ini masalah gambar referensi, bukan masalah volume, dengan tulisannya sendiri soal konsistensi.
Untuk beban kerja campuran, jalankan bagian terbesarnya di Lite dan cabangkan 2% yang butuh teks atau kesetiaan ke Pro lewat sebuah kolom di data Anda. Satu pipeline, dua model, harga Pro hanya di tempat ia menghasilkan sesuatu.
Untuk penelusuran parameter demi parameter atas kontrak submit dan polling, lihat tutorial API Nano Banana Pro, dan untuk rincian tier demi tier, perbandingan modelnya. Keduanya mengandaikan Anda sudah memilih sebuah model. Kalau belum, model text-to-image terdaftar lengkap dengan harganya, dan katalog menambahkan sisi videonya.
Semuanya, berurutan
Template dengan slot. Data dengan ID yang stabil. Kirim sebagai job di bawah plafon yang keras. Ambil sebuah webhook. Unduh byte-nya ke penyimpanan Anda sendiri. Catat kegagalan dan pengeluarannya. Enam langkah, tidak satu pun sulit, dan yang selalu dilewati adalah langkah kelima.
Pertanyaan yang sering diajukan
Bagaimana cara menghasilkan gambar secara otomatis?
Tulis prompt Anda sebagai template dengan slot bernama, isi slot itu dari sebuah sumber data seperti katalog produk atau CSV, dan kirim tiap prompt yang sudah terisi sebagai job asinkron ke sebuah API gambar. Ambil hasilnya lewat webhook alih-alih polling, lalu unduh byte gambarnya ke penyimpanan Anda sendiri. Tidak ada di dalam loop itu yang butuh manusia, dan itulah yang membuatnya otomatis alih-alih kerja manual yang cepat.
Berapa biaya menghasilkan 1.000 gambar secara otomatis?
Pada harga E2X tanggal 26 Agustus 2026, 1.000 gambar lewat Nano Banana 2 Lite adalah $23.80, karena tiap request $0.0238. Volume yang sama adalah $40.00 di Nano Banana 2 dan $75.00 di Nano Banana Pro. Resolusi yang lebih tinggi mengalikan di atasnya, tetapi untuk output 1K standar angka per gambar itulah seluruh perhitungannya.
Sebaiknya saya memakai webhook atau polling untuk job generasi gambar?
Pakai webhook untuk apa pun yang berjalan tanpa ditunggui. Polling mengikat masa hidup proses Anda ke job paling lambat di dalam batch, jadi sebuah deploy atau timeout serverless membunuh poller-nya selagi ia memegang satu-satunya catatan tentang job mana yang masih berjalan. Webhook membuat Anda bisa mengirim lalu keluar, kemudian menangani tiap job yang selesai tanpa state. Polling tidak masalah untuk script yang Anda tonton berjalan.
Kenapa gambar yang saya hasilkan berhenti termuat setelah beberapa waktu?
Karena Anda menyimpan URL output API alih-alih gambarnya. URL itu pengiriman yang sementara, bukan penyimpanan, jadi kolom yang memuatnya tampil benar mula-mula dan patah kemudian. Unduh byte-nya begitu job-nya selesai, tuliskan ke bucket Anda sendiri, simpan URL Anda sendiri. Ini cara paling umum sebuah pipeline gambar dirilis dalam keadaan rusak.
Model apa yang sebaiknya menjadi default sebuah pipeline gambar otomatis?
Nano Banana 2 Lite, pada $0.0238 per gambar. Ia model gambar termurah di katalog kami dan satu generasi lebih baru daripada Nano Banana asli, dan pada volume batch harga mendominasi setiap pertimbangan lain. Pindah ke Nano Banana 2 hanya untuk output di atas 1K, ke Nano Banana Pro hanya untuk teks dalam gambar yang terbaca, dan ke GPT Image 2 hanya untuk latar transparan.
Apa yang terjadi ketika sebagian gambar dalam satu batch gagal?
Sebagian selalu akan gagal, dan pipeline-nya sebaiknya memperlakukan itu sebagai normal alih-alih fatal. Teruslah mengirim setelah sebuah baris ditolak, catat ID yang gagal beserta error-nya, dan bangun jalur retry yang menjalankan kegagalannya saja. Batasi jumlah percobaan retry, karena masing-masing adalah tagihan sungguhan.