Skip to content
Open app

SDK quickstart

These examples use the official google-genai Python SDK and a Moonez.ai key with permission for the selected model. See Authentication and the Gemini-compatible API overview.

Terminal window
pip install --upgrade google-genai
export MOONEZ_API_KEY="YOUR_MOONEZ_API_KEY"
import os
from google import genai
from google.genai import types
client = genai.Client(
api_key=os.environ["MOONEZ_API_KEY"],
http_options=types.HttpOptions(
base_url="https://api.moonez.ai/api/gemini/v1beta",
base_url_resource_scope=types.ResourceScope.COLLECTION,
),
)

The base URL already includes /v1beta. ResourceScope.COLLECTION prevents the SDK from adding the version again. This is the Google SDK’s supported custom base URL configuration.

In Android apps and other clients with a custom Gemini provider, enter https://api.moonez.ai/api/gemini/v1beta in the Base URL field and use your Moonez.ai key. Requests should target /api/gemini/v1beta/models/..., without a duplicate /v1beta.

from pathlib import Path
response = client.models.generate_content(
model="gemini-nano-banana-2.1",
contents="Draw a red panda astronaut against a nebula.",
config=types.GenerateContentConfig(response_modalities=["IMAGE"]),
)
for part in response.candidates[0].content.parts:
if part.inline_data:
Path("out.png").write_bytes(part.inline_data.data)
break

In JSON, the image is base64-encoded in inlineData.data within one of the response parts. The Python SDK already returns inline_data.data as bytes. The image is not necessarily the first part; if generation is blocked, the provider may not return an image at all.

This example omits aspectRatio; Moonez.ai does not add it automatically.

Use gemini-3.1-flash-lite-image with a key that has its separate model permission. It supports 1K output only and has its own tariff:

response = client.models.generate_content(
model="gemini-3.1-flash-lite-image",
contents="A ceramic cup in soft studio lighting.",
config=types.GenerateContentConfig(
response_modalities=["IMAGE"],
image_config=types.ImageConfig(image_size="1K"),
),
)

Read image bytes from the response parts as in the example above. Do not use 2K or 4K for this model. For a native job, see the Lite reference.

To set them explicitly, pass this config to generate_content:

config = types.GenerateContentConfig(
response_modalities=["IMAGE"],
image_config=types.ImageConfig(
aspect_ratio="16:9",
image_size="2K",
),
)

Nano Banana 2.1, gemini-3.1-flash-image, and gemini-3-pro-image support 1K, 2K, and 4K. gemini-3.1-flash-image also supports 512px; gemini-2.5-flash-image outputs 1K. 512px is billed at the 1K rate. gemini-3.1-flash-lite-image is also 1K only. The provider validates the supplied parameters.

Pass an image and an instruction in contents:

from pathlib import Path
response = client.models.generate_content(
model="gemini-nano-banana-2.1",
contents=[
types.Part.from_bytes(
data=Path("input.png").read_bytes(),
mime_type="image/png",
),
"Add a tiny astronaut helmet.",
],
config=types.GenerateContentConfig(response_modalities=["IMAGE"]),
)
for part in response.candidates[0].content.parts:
if part.inline_data:
Path("edited.png").write_bytes(part.inline_data.data)
break

The SDK reads the SSE stream returned by streamGenerateContent:

for chunk in client.models.generate_content_stream(
model="gemini-3.8-flash",
contents="Write a haiku about servers.",
):
if chunk.text:
print(chunk.text, end="")

When the provider returns usageMetadata, those confirmed counters are used to calculate the text generation cost.

response = client.models.generate_content(
model="gemini-4-argon",
contents="Explain quantum computing in one sentence.",
)
print(response.text)

countTokens requests a token count from the provider and is free of charge on Moonez.ai. Availability depends on the model and provider.

response = client.models.count_tokens(
model="gemini-4-argon",
contents="How many tokens is this?",
)
print(response.total_tokens)
for model in client.models.list():
print(model.name)

GET /models returns the image, text, and Omni models permitted by your key, without pagination. It excludes Veo, which uses the asynchronous video API. See the complete model catalog for all 18 IDs.

Errors use the standard Gemini structure:

HTTP statusCodeMeaning
400INVALID_ARGUMENTInvalid request parameters
403PERMISSION_DENIEDThe key lacks permission for the model
404NOT_FOUNDModel or method not found
429RESOURCE_EXHAUSTEDRequest or quota limit reached
503UNAVAILABLEService temporarily unavailable

Use retries with increasing delays for transient errors. You can configure them using the SDK’s built-in retry options.