SDKs
Node SDK
The official dhanu npm package, install it, generate images and text, and handle errors with DhanuError.
The dhanu package wraps the public API for Node. It has no dependencies and uses
the global fetch, so it needs Node 18 or newer.
Install
npm i dhanu
Set up the client
import { Dhanu } from "dhanu";
// Server-side only, never ship your secret key to a browser.
const dhanu = new Dhanu(process.env.DHANU_API_KEY!);
The key is always passed explicitly. There is no baseUrl option: the base URL
comes from DHANU_BASE_URL if set, and otherwise defaults to
https://api.dhanu.ai. Point DHANU_BASE_URL at http://localhost:3000 for local
development.
Generate an image
import { writeFileSync } from "node:fs";
const image = await dhanu.images.generate({
prompt: "a red bicycle on a white background",
aspectRatio: "1:1", // "1:1" | "3:4" | "9:16" | "4:3" | "16:9"
});
writeFileSync("out.png", Buffer.from(image.b64, "base64"));
Returns { b64, mimeType, model, usage, cost }. Nothing is stored server-side,
see Generate an image.
Generate text
const reply = await dhanu.text.generate({
prompt: "Write a haiku about Kathmandu",
system: "You are a concise poet.",
maxTokens: 200,
});
console.log(reply.text);
Returns { text, model, usage, cost }.
Verify a key
const me = await dhanu.me();
Typed requests and responses
Every request body, query and response is generated from the API contract into
ApiTypes, so the wire shape your code compiles against is the one the server
validates. The resource methods already return these types, dhanu.tasks.create
returns ApiTypes.TasksCreateResponse["task"], and you can name them directly
when you keep a value around:
import type { ApiTypes } from "dhanu";
const body: ApiTypes.TasksCreateRequest = { input: "Summarise the week", fileIds };
const task = await dhanu.tasks.create(body);
Retries and timeouts
Every call is retried up to twice on a network error, a timeout, 408, 429 or a
5xx, waiting for Retry-After when the server sends one and backing off
exponentially (500 ms, 1 s, 2 s… capped at 8 s) otherwise. JSON POSTs carry a
generated Idempotency-Key on every attempt, so a retry can never run the same call
twice. Each attempt is aborted after 60 s. Tune or switch it off per client:
const dhanu = new Dhanu(process.env.DHANU_API_KEY!, { maxRetries: 0, timeoutMs: 10_000 });
A request that never reached the server throws DhanuError with status: 0 and
code: "network_error" or "timeout".
Handle errors
Every failure throws DhanuError with a machine-readable code, the HTTP
status, a message, and the requestId to quote in support reports.
import { DhanuError } from "dhanu";
try {
await dhanu.images.generate({ prompt: "…" });
} catch (err) {
if (err instanceof DhanuError) {
if (err.code === "rate_limited") {
// back off and retry, see /developer/reference/rate-limits
}
console.error(err.code, err.status, err.message, err.requestId);
}
}
The complete list of codes is on Errors.