03Getting started
Libraries for Python and Node.jsNew
Ready-made clients take care of the idempotency key, waiting for the result, and checking the webhook signature. The same five API methods, with less code.
This model doesn’t produce every resolution and aspect ratio: the examples use the ones available to it.
Installation
# Python 3.11 and newer
$ pip install rendergrid# Node.js 22 and newer
$ npm install @rendergrid/sdkThe libraries take the key from the RENDERGRID_API_KEY environment variable. You can pass another source explicitly: Rendergrid(api_key=…).
First image
from rendergrid import Rendergrid client = Rendergrid() # the key is taken from RENDERGRID_API_KEY creation = client.images.generate( model="nano-banana-pro", prompt="A ceramic mug on marble, soft window light", resolution="1K", aspect_ratio="4:5", ) print(creation.id, creation.status, creation.cost) result = creation.wait(timeout=180) # polls no more often than once every 5 seconds print(result.result_urls)
import { Rendergrid } from "@rendergrid/sdk"; // the key is taken from RENDERGRID_API_KEY const client = new Rendergrid(); const creation = await client.images.generate({ model: "nano-banana-pro", prompt: "A ceramic mug on marble, soft window light", resolution: "1K", aspect_ratio: "4:5", }); console.log(creation.id, creation.status, creation.cost); // polls no more often than once every 5 seconds const result = await creation.wait({ timeoutMs: 180_000 }); console.log(result.result_urls);
generate sends the request and returns the accepted task. wait polls it until it becomes completed or failed. If there is no result within the allotted time, you get an error with the task id—you can continue later.
What the library does for you
| Task | What the library does | More |
|---|---|---|
| Idempotency key | Creates X-Idempotency-Key itself and keeps it across retries | Idempotency |
| Retries | On a dropped connection, 429, and 5xx, repeats the request up to three times and waits at least Retry-After. A response that itself says a retry is not needed is not retried. A reference upload (uploads.create) is retried only when the request definitely did not reach the API: after 429, 503, or a refused connection | Limits |
| Waiting | Polls the task no more often than once every 5 seconds and respects min_interval_seconds | Tasks and statuses |
| Errors | Turns a response into an exception with the fields status, code, retryable, and details | Error codes |
| Webhooks | Checks the signature and the freshness of the timestamp and returns the parsed event | Webhooks |
| Money | Returns amounts as Decimal in Python and as strings in Node.js, not as floating-point numbers | Balance |
Errors
import time import rendergrid try: creation = client.images.generate( model="nano-banana-pro", prompt="A ceramic mug on marble", ) except rendergrid.InsufficientBalance as e: need, have = e.details["required"], e.details["available"] print("Required:", need, "available:", have) except rendergrid.RateLimited as e: time.sleep(e.retry_after) except rendergrid.APIError as e: print(e.status, e.code, e.retryable)
import { RendergridError } from "@rendergrid/sdk"; try { const creation = await client.images.generate({ model: "nano-banana-pro", prompt: "A ceramic mug on marble", }); } catch (error) { if (!(error instanceof RendergridError)) throw error; if (error.code === "ERR_INSUFFICIENT_BALANCE") { const { required, available } = error.details; console.log("Required:", required, "available:", available); } else { console.log(error.status, error.code, error.retryable); } }
Error classes are named after the code from the API: ERR_INSUFFICIENT_BALANCE is InsufficientBalance, and ERR_RATE_LIMIT is RateLimited. Everything else is the general APIError.
Webhooks
import os from flask import Flask, request from rendergrid.webhooks import verify app = Flask(__name__) @app.post("/webhooks/rendergrid") def hook(): event = verify( secret=os.environ["RENDERGRID_WEBHOOK_SECRET"], headers=request.headers, body=request.get_data(), # the raw bytes, not request.json ) if not event.get("test"): save_result( event["id"], event["status"], event.get("result_urls") ) return "", 204
import express from "express"; import { verifyWebhook } from "@rendergrid/sdk/webhooks"; const app = express(); const raw = express.raw({ type: "application/json" }); app.post("/webhooks/rendergrid", raw, (req, res) => { const event = verifyWebhook({ secret: process.env.RENDERGRID_WEBHOOK_SECRET, headers: req.headers, body: req.body, // Buffer: the raw bytes of the body }); if (!event.test) { saveResult(event.id, event.status, event.result_urls); } res.sendStatus(204); });
The signature is computed over the raw bytes of the body. If the framework has already parsed the JSON and rebuilt it, the signature will not match.
Versions and other languages
- Python
- 3.11 and newer. The
rendergridpackage on PyPI. - Node.js
- 22 and newer. The
@rendergrid/sdkpackage on npm; it also works with TypeScript. - API versions
- The libraries work with API v1. New fields in responses do not break older versions of the libraries.
A library is not required: everything it does can be done with ordinary HTTPS requests, as in the “Quickstart.” Your language is not covered? Take the OpenAPI description and generate a client.