Nano Banana Pro API कैसे कॉल करें: शुरू से आख़िर तक
यह E2X API पर Nano Banana Pro का पूरा इंटीग्रेशन है, शुरू से आख़िर तक। key लीजिए, job submit कीजिए, response पढ़िए, ढंग से इंतज़ार कीजिए, फ़ेल होने के तरीक़े सँभालिए, और bytes ऐसी जगह रखिए जो कल भी मौजूद होगी।
आख़िरी क़दम ही लोगों को पकड़ता है। अगर आप पहले से इमेज बना रहे हैं और सिर्फ़ यह जानना चाहते हैं कि आपकी इमेज ग़ायब क्यों हो गईं, तो सीधे वहीं चले जाइए।

आपके काम के लिए Pro सही टियर है या नहीं, यह अलग सवाल है और उसका जवाब हमने अलग से दिया है, कीमत और रफ़्तार वाली पोस्ट में। छोटा जवाब: $0.075 प्रति request, क़रीब 30 सेकंड, और वाजिब तब जब आपकी इमेज पढ़ने लायक़ टेक्स्ट ढोती हों या अलग-अलग रोल निभाती references जोड़ती हों। यह पेज मानकर चलता है कि आप तय कर चुके हैं।
पहली request से पहले क्या चाहिए
चार चीज़ें, और उनमें से तीन एक-एक लाइन की हैं।
- एक API key. अपने E2X अकाउंट से बनाइए। नीचे की हर चीज़ उसे
Authorization: Bearer $E2X_API_KEYके तौर पर भेजती है। इसे server-side रखिए। ब्राउज़र के JavaScript में पड़ी key वह key है जिसे अब कोई और ख़र्च कर रहा है। - Base URL, जो कैटलॉग के हर मॉडल के लिए
https://api.e2x.ai/v1है। - सही slug. जनरेशन
google/nano-banana-pro/text-to-imageहै। एडिटिंगgoogle/nano-banana-pro/edit-image। ये strings request body में हूबहू जाती हैं, और इन पर कोई fuzzy matching नहीं होती। - भेजने लायक़ एक prompt. Pro बारीकी को flash टियरों से ज़्यादा इनाम देता है, क्योंकि उस पर अमल करने की उसके पास ज़्यादा जगह है। अगर आप "एक बिल्ली, पर cinematic" से आगे जाना चाहते हैं तो हमारी अलग prompting गाइड है।
contract asynchronous है। आप एक job submit करते हैं, आपको एक ID मिलती है, और इमेज बाद में आती है। कोई synchronous endpoint नहीं है जो pixels तैयार होने तक अटका रहे — और चूँकि Pro क़रीब 30 सेकंड लेता है, आप ऐसा चाहेंगे भी नहीं।
आपकी पहली text-to-image request
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": "संगमरमर के कॉफ़ी काउंटर के पीछे हाथ से लिखा चॉकबोर्ड मेन्यू, बाईं तरफ़ की खिड़की से आती गरम दोपहर की रोशनी, shallow depth of field",
"aspect_ratio": "16:9",
"resolution": "2k"
}
}'
वही चीज़ 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"]
दोनों उदाहरण जानबूझकर aspect_ratio और resolution pin करते हैं, और इन्हें हटाने से पहले दोनों डिफ़ॉल्ट समझ लेना ठीक रहेगा।
aspect_ratio का डिफ़ॉल्ट 9:16 है। 1:1 नहीं। अगर आप इसे छोड़ देंगे, तो आपकी बनाई हर इमेज हमेशा के लिए portrait होगी, और आपको तब तक पता नहीं चलेगा जब तक आपके लेआउट का कोई चौड़ा ख़ाना ग़लत न दिखने लगे। हमारे API के किसी भी दूसरे फ़ील्ड से ज़्यादा इंटीग्रेशन यही गिराता है। इसे pin कीजिए।
resolution के मान छोटे अक्षरों में हैं। 1k, 2k, 4k। बड़े अक्षरों वाला 2K वही string नहीं है और API आपको यह बता देगा।
इस slug पर 1k को मरा हुआ मान मानिए। पहली दो सेटिंग्स एक ही सपाट शुल्क पर बैठती हैं — दोनों के लिए $0.075, 26 अगस्त 2026 को जाँचा हुआ — इसलिए छोटा वाला उसी इनवॉइस लाइन के बदले बस कम pixels लौटाता है। नंबर सिर्फ़ 4k हिलाता है: $0.15, छत 4096×4096।

वापस क्या आता है
submit कॉल फ़ौरन एक job envelope के साथ लौटती है। आपको जो फ़ील्ड चाहिए वह data.jobId है:
{
"success": true,
"data": {
"jobId": "job_8Kd2mQvXpL",
"status": "pending"
}
}
Status pending → processing → completed की तरफ़ बढ़ता है, या दो अंतिम विफलताओं में से एक पर उतरता है, failed और cancelled। पूरी हुई job अपना नतीजा data.outputs[0].url पर ढोती है, और फ़ेल हुई job अपनी वजह data.error.message पर।
कोई भी billing कोड लिखने से पहले एक बात भीतर बिठा लीजिए: API जो भी पैसे का मान लौटाता है वह micro-cents में है। दस लाख यानी एक डॉलर। इसलिए Nano Banana Pro की request 75000 बनकर लौटती है, 0.075 नहीं। 1,000,000 से भाग सिर्फ़ display परत पर दीजिए और कहीं नहीं, और भाग दिया हुआ नंबर कभी स्टोर मत कीजिए।
हथौड़ा चलाए बिना polling
सीधा-सादा तरीक़ा काम करता है:
curl https://api.e2x.ai/v1/jobs/job_8Kd2mQvXpL \
-H "Authorization: Bearer $E2X_API_KEY"
इसे दो सेकंड की तय नींद वाले loop में लपेटिए और आपका इंटीग्रेशन चालू है। ख़ास तौर पर Nano Banana Pro के लिए तय अंतराल सचमुच स्वीकार्य है — एक request क़रीब 30 सेकंड चलती है, इसलिए आप मोटे तौर पर पंद्रह status कॉल करके रुक जाते हैं। इतना ट्रैफ़िक किसी को परेशान नहीं करता।
फिर भी backoff बेहतर है, और वजह शिष्टाचार से कोई लेना-देना नहीं रखती। तय अंतराल विचरण को छिपा देते हैं। अगर कोई job 30 की जगह 90 सेकंड लेती है, तो तय loop उसी दर से कॉल करता रहता है और आपके logs एक स्वस्थ run जैसे ही दिखते हैं। बढ़ता हुआ backoff धीमी job को दिखने में भी धीमा बना देता है।
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")
यह loop दो चीज़ें करता है जो कोई भोला loop आमतौर पर नहीं करता। इसमें एक पक्की समयसीमा है, इसलिए अटकी हुई job प्रोसेस के मारे जाने तक घूमने के बजाय error उठाती है। और यह transport परत पर तीनों अंतिम हालतों के साथ एक ही बर्ताव करता है — payload लौटा देता है और यह तय करना कॉल करने वाले पर छोड़ देता है कि विफलता का मतलब क्या है। Retry का तर्क इस function के भीतर नहीं, इसके ऊपर रहता है।

Webhooks, और आपको उन पर क्यों जाना चाहिए
submit body में webhookUrl भेजिए और job के किसी अंतिम हालत पर पहुँचते ही हम आपको कॉल करते हैं। कोई polling loop नहीं।
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": "drafting टेबल पर एक पैदल पुल का वास्तु मॉडल, उत्तर दिशा की रोशनी",
"aspect_ratio": "3:2",
"resolution": "2k"
},
"webhookUrl": "https://your-app.example.com/hooks/e2x"
}'
पहला क़दम polling ही सही है, क्योंकि आप उसे दस सेकंड में टर्मिनल से जाँच सकते हैं। स्थायी हालत के लिए वह ग़लत है, और वजह हिसाब है। एक बार में एक इमेज पर polling की कीमत एक loop है। batch में दो सौ इमेज पर polling की कीमत दो सौ समांतर loops है, हर एक आधे मिनट तक एक connection थामे हुए, और वह भी ऐसी प्रोसेस में जिसे अब बिना हर उड़ती हुई job का हिसाब खोए दोबारा शुरू ही नहीं किया जा सकता।
Webhooks काम को दोबारा शुरू करने लायक़ बना देते हैं। submit करते वक़्त job ID आपके डेटाबेस में जाती है, हमारे कॉल करने पर handler पंक्ति अपडेट कर देता है, और बीच में हुआ कोई deploy कुछ नहीं बदलता। अगर आप स्क्रिप्ट नहीं, generation pipeline बना रहे हैं, तो यही संस्करण बनाइए — और यह इमेज जनरेशन को सिरे से सिरे तक ऑटोमेट करना वाली हमारी पोस्ट के पैटर्नों से जुड़ता है।
दो व्यावहारिक बातें। आपका endpoint सार्वजनिक इंटरनेट से पहुँच में होना चाहिए, इसलिए localhost वाला URL डेवलपमेंट के दौरान चुपचाप कभी नहीं चलेगा — tunnel इस्तेमाल कीजिए। और webhook को सूचना मानिए, सच का स्रोत नहीं: handler के भीतर उस पर अमल करने से पहले job को ID से fetch कीजिए।
जनरेट करने के बजाय इमेज एडिट करना
वही envelope, अलग slug, एक अतिरिक्त फ़ील्ड। Edit endpoint prompt के साथ image_urls लेता है और उतने ही $0.075 का पड़ता है।
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": "background को नरम धूसर studio sweep से बदलिए, प्रोडक्ट की रोशनी बिलकुल वैसी ही रखिए",
"image_urls": ["https://your-cdn.example.com/source/bottle.jpg"],
"aspect_ratio": "1:1",
"resolution": "2k"
}
}'
आप जो URLs भेजते हैं, वे सार्वजनिक रूप से fetch किए जा सकने चाहिए। आपके अपने स्टोरेज से आया signed URL चलेगा; आपके लैपटॉप का कोई path नहीं चलेगा।
Nano Banana Pro चौदह reference इमेज तक लेता है, और बाक़ी टियरों के उलट उन्हें रोल के हिसाब से बाँटता है — कैरेक्टर की पहचान के लिए 5 तक, ऑब्जेक्ट की fidelity के लिए 6 तक, स्टाइल के लिए 3 तक। इस टियर पर होने की वजह ही वह रोल-बँटवारा है, और रोल-आधारित references के सटीक फ़ील्ड नाम हर मॉडल के लिए मशीन-पठनीय spec फ़ाइल में दर्ज हैं — और अगर हमारे डॉक्स और यह पोस्ट कभी असहमत हों, तो प्रामाणिक वही है। ख़ास तौर पर कैरेक्टर-consistency वाले workflow पर हम एक जैसी इमेज बनाने की गाइड में गहरे जाते हैं।
हर पैरामीटर, और उसका डिफ़ॉल्ट
| फ़ील्ड | कहाँ जाता है | स्वीकार्य मान | डिफ़ॉल्ट |
|---|---|---|---|
model | body की जड़ | google/nano-banana-pro/text-to-image या google/nano-banana-pro/edit-image | ज़रूरी |
input.prompt | input के भीतर | string | ज़रूरी |
input.aspect_ratio | 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 | input के भीतर | 1k, 2k, 4k | साफ़-साफ़ pin कीजिए |
input.image_urls | input के भीतर, सिर्फ़ edit slug पर | सार्वजनिक रूप से पहुँच में आने वाले URLs की array | edit पर ज़रूरी |
webhookUrl | body की जड़ | कोई सार्वजनिक HTTPS endpoint | कोई नहीं, इसके बजाय poll कीजिए |
लोगों का पैसा जो दो पंक्तियाँ खाती हैं वे aspect_ratio और resolution हैं। बाक़ी सब वैसा ही बर्ताव करता है जैसा आप अंदाज़ा लगाएँगे।
जब job पूरी नहीं होती
तीन विफलता सतहें, और हर एक को अलग सँभाल चाहिए।
submit कॉल ख़ुद फ़ेल हो जाती है। यह किसी job के बनने से पहले की HTTP error है — ग़लत key, बिगड़ी हुई body, अनजान मॉडल slug। कुछ भी queue नहीं हुआ और कोई शुल्क नहीं लगा। request ठीक कीजिए; उसे बिना बदले दोबारा भेजने पर वैसे ही फ़ेल होगी।
job failed तक पहुँचती है। job बनी थी और मॉडल ने इमेज नहीं बनाई। वजह के लिए data.error.message पढ़िए, जो आमतौर पर content policy की मनाही होती है या कोई बिगड़ा हुआ input, जैसे image_urls में न पहुँचने लायक़ URL। policy की मनाही पर आँख मूँदकर किया गया retry उसी तरह फ़ेल होता है; किसी क्षणिक upstream error के बाद का retry आमतौर पर चल जाता है। संदेश दर्ज कीजिए, सिर्फ़ status मत दर्ज कीजिए।
job cancelled तक पहुँचती है। अंतिम हालत, और bug नहीं। कोड के स्तर पर इसे ठीक failed जैसा ही मानिए — पंक्ति बंद हो चुकी है, कोई output नहीं आ रहा।
आपका wait loop timeout हो जाता है। यह job की हालत नहीं है। इसका मतलब है कि job अब भी चल रही है और आपका सब्र ख़त्म हो गया। job ID अब भी वैध है, इसलिए उसे दर्ज कीजिए और बाद में दोबारा जाँचिए — दोबारा submit मत कीजिए, वरना उसी इमेज के दो बार पैसे लगेंगे।
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"]
मियाद ख़त्म होने से पहले output डाउनलोड कीजिए
यही वह हिस्सा है जो लॉन्च के एक हफ़्ते बाद टूटी हुई इमेज ship कर देता है, इसलिए इसे अपना अलग सेक्शन मिला है।
data.outputs[0].url पर मौजूद URL अस्थायी है। वह delivery URL है, hosting नहीं। अगर आप उस string को image_url नाम के डेटाबेस कॉलम में लिखकर किसी प्रोडक्ट पेज पर render करेंगे, तो पेज staging में चलेगा, समीक्षा में चलेगा, लॉन्च के दिन चलेगा, और फिर ऑब्जेक्ट की उम्र पूरी होते ही चुपचाप टूटे इमेज आइकॉन में बदल जाएगा।
इलाज एक क़दम का है और वैकल्पिक नहीं है। bytes fetch कीजिए, उन्हें अपने स्टोरेज में रखिए, अपना URL स्टोर कीजिए।
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
या shell से:
curl -sL "$OUTPUT_URL" -o ./out/menu-board.jpg
डाउनलोड उसी काम की इकाई के भीतर कीजिए जिसने पूरा होना सँभाला। एक घंटे बाद के किसी cron पर नहीं, पहली बार पेज खुलने पर आलस से नहीं। खिड़की इतनी उदार है कि टेस्टिंग में देरी से आप बच जाएँगे, और इतनी सँकरी कि load के नीचे नहीं बचेंगे।

पूरी चीज़, एक स्क्रिप्ट के रूप में
ऊपर का सब कुछ, जोड़ा हुआ। E2X_API_KEY सेट कीजिए और चला दीजिए।
#!/usr/bin/env python3
"""Nano Banana Pro से एक इमेज बनाकर उसे लोकल स्टोर करता है।"""
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(
"संगमरमर के कॉफ़ी काउंटर के पीछे हाथ से लिखा चॉकबोर्ड मेन्यू, "
"बाईं तरफ़ की खिड़की से आती गरम दोपहर की रोशनी, shallow depth of field"
)
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()
slug को google/nano-banana-pro/edit-image से बदलिए और image_urls जोड़ दीजिए, वही स्क्रिप्ट बनाने के बजाय एडिट करने लगेगी। उसे Nano Banana 2 या Nano Banana 2 Lite से बदल दीजिए, वह तब भी चलेगी, क्योंकि envelope text-to-image कैटेगरी की हर चीज़ और image-to-image की हर चीज़ पर एक जैसा है। सिर्फ़ input के फ़ील्ड बदलते हैं, और उसे किस पर टिकाना है यह मॉडल तुलना वाली पोस्ट समेटती है।
एक आख़िरी बात, जो कोड नहीं है। Google के हर मॉडल से आई हर इमेज पर SynthID watermark होता है और कोई provider उसे बंद नहीं कर सकता। इस पर कुछ बनाने से पहले उसे उस इंसान के साथ सुलझा लीजिए जो contract पर दस्तख़त करता है।
अक्सर पूछे जाने वाले सवाल
मैं Nano Banana Pro API कैसे कॉल करूँ?
https://api.e2x.ai/v1/jobs/submit पर एक POST भेजिए, साथ में bearer token, मॉडल slug google/nano-banana-pro/text-to-image, और आपके prompt वाला एक input ऑब्जेक्ट। response data.jobId लौटाता है। https://api.e2x.ai/v1/jobs/{id} को poll कीजिए या submit body में webhookUrl भेजिए, फिर तैयार इमेज data.outputs[0].url से पढ़िए।
Nano Banana Pro का डिफ़ॉल्ट aspect ratio क्या है?
9:16, यानी portrait। यह लगभग सबको चौंकाता है, क्योंकि ज़्यादातर इमेज API का डिफ़ॉल्ट वर्ग होता है। अगर आप aspect_ratio साफ़-साफ़ सेट नहीं करेंगे, तो हर इमेज खड़ी निकलेगी। मॉडल 9:16, 16:9, 1:1, 2:3, 3:2, 21:9, 3:4, 4:3, 4:5 और 5:4 लेता है।
मेरा Nano Banana Pro इमेज URL टूटा हुआ क्यों है?
क्योंकि हम जो output URL लौटाते हैं वह अस्थायी delivery है, स्थायी hosting नहीं। जो भी pipeline हमारा URL डेटाबेस में सहेजकर बाद में render करती है, वह ऑब्जेक्ट की मियाद ख़त्म होते ही टूटी इमेज दिखाएगी। bytes उसी क़दम में डाउनलोड कीजिए जो job का पूरा होना सँभालता है, और उन्हें अपने bucket में रखिए।
E2X API के साथ मुझे polling इस्तेमाल करनी चाहिए या webhooks?
बनाते वक़्त poll कीजिए, क्योंकि उसे टर्मिनल से जाँचा जा सकता है। प्रोडक्शन में चलने वाली हर चीज़ के लिए webhooks पर जाइए। Nano Banana Pro की एक job क़रीब 30 सेकंड लेती है, इसलिए दो सौ का batch यानी दो सौ समांतर polling loops, जो अगले deploy पर अपना state खो देंगे। webhookUrl के साथ job ID submit के वक़्त ही आपके डेटाबेस में चली जाती है और handler उसे बाद में उठा लेता है।
Nano Banana Pro से मौजूदा इमेज कैसे एडिट करूँ?
slug google/nano-banana-pro/edit-image इस्तेमाल कीजिए और input ऑब्जेक्ट में prompt के साथ एक image_urls array जोड़िए। URLs सार्वजनिक रूप से fetch किए जा सकने चाहिए, इसलिए आपके स्टोरेज से आया signed URL चलेगा और कोई लोकल path नहीं चलेगा। एडिटिंग जनरेशन जितनी ही, $0.075 की पड़ती है।
Nano Banana Pro से मुझे कौन-सी resolution माँगनी चाहिए?
2k भेजिए। इस slug पर पहली दो सेटिंग्स एक ही सपाट शुल्क साझा करती हैं, इसलिए 1k सीधे-सीधे हारा हुआ है — कम pixels, वही इनवॉइस लाइन। 4k तभी उठाइए जब आपको सचमुच 4096×4096 की छत चाहिए, क्योंकि वह शुल्क दोगुना करके $0.15 कर देता है। तीनों मान छोटे अक्षरों में हैं।
E2X API 75000 जैसी कीमतें क्यों लौटाता है?
API में पैसे का हर मान micro-cents में लिखा जाता है, जहाँ 1,000,000 यानी एक अमेरिकी डॉलर। किसी Nano Banana Pro job पर 75000 का मतलब $0.075 है। पूर्णांक को स्टोरेज में रखिए और भाग सिर्फ़ वहीं दीजिए जहाँ कोई इंसान उसे पढ़ता है, ताकि पूरे बिलिंग काल में गोल करने की ग़लती जुड़ती न जाए।