TypeScript SDK
The Fuel SDK for your server and your users' wallets. Launches, tokens, credit, keys, webhooks and the Fuel Router, typed end to end.
@fuelpad/sdk is the official SDK for the management API and the Fuel Router. It runs on Node.js 22+, Bun, Deno, Cloudflare Workers and Vercel Functions, with one small dependency.
npm i @fuelpad/sdkSet up
Make a secret key on the dashboard's Keys page and keep it on your server:
import { Fuel } from "@fuelpad/sdk";
// Reads FUEL_SECRET_KEY.
const fuel = new Fuel();The client refuses to run in a browser, where the key would reach every visitor. Its parts for the browser live in @fuelpad/sdk/solana.
Launch a token
const launch = await fuel.launches.prepare(
{
creator: wallet, // signs last and pays
name: "Acme",
symbol: "ACME",
image: await fuel.files.dataUri(file),
transaction_version: version, // from the browser
},
{ idempotencyKey: `launch:${draftId}` },
);
// Later, with the signed transaction from the browser:
await fuel.launches.submit(launch.id, { transaction: signed });
// "confirmed", "failed" or "expired".
const { state } = await fuel.launches.wait(launch.id);files.dataUri() checks the image (PNG, JPEG, GIF or WebP, up to 2 MB) before it leaves your server. signWithWallet refuses a transaction the wallet changed while signing, which the API would reject. Bring a token works the same with fuel.tokens.import({ mint, creator }).
Tokens, credit and keys
// Every token, page by page.
for await (const token of fuel.tokens.all()) {
console.log(token.mint, token.preset?.name);
}
// The token's credit account, and a router key for its agent.
const account = await fuel.accounts.get(mint);
const key = await fuel.keys.create({
account: account.id,
name: "agent-1",
limit: { usd: "5", reset: "daily" },
});key.key (fl_ai_...) is shown once, as on the dashboard. The resources follow the API reference: launches, tokens, presets, accounts (with ledger and purchases), keys, usage, statements and webhooks, with the API's own field names.
Webhooks
import { verifyWebhook } from "@fuelpad/sdk/webhooks";
export async function POST(request: Request): Promise<Response> {
const event = await verifyWebhook({
body: await request.text(), // the raw body
header: request.headers.get("fuel-signature"),
secret: process.env.FUEL_WEBHOOK_SECRET!, // whsec_...
});
if (event.type === "launch.confirmed") {
// event.data.launch
}
return new Response(null, { status: 204 });
}During a rotation, pass both secrets: secret: [current, previous]. See Webhooks.
The Fuel Router
// Reads FUEL_ROUTER_KEY (fl_ai_...).
const { spendable_usd } = await fuel.ai.balance();
const { data, usage } = await fuel.ai.images.generate({
model: "openai/gpt-image-2",
prompt: "A red lighthouse at dusk, flat illustration",
});ai.models() and ai.imageModels() list every model with its price, and ai.images.stream() yields partial images as they form. For chat, use the OpenAI or Anthropic SDK with fuel.ai.baseURL, or the Vercel AI SDK provider.
Errors and retries
import { isAPIError } from "@fuelpad/sdk";
try {
await fuel.launches.prepare(params);
} catch (error) {
if (isAPIError(error) && error.code === "insufficient_funds") {
// error.status, error.param, error.requestId
} else {
throw error;
}
}error.codeis the API's stable error code; quoteerror.requestIdto support.- Network errors, timeouts,
429and5xxare retried twice, waiting asRetry-Afterasks. - Every
POSTcarries anIdempotency-Key, so a retry never acts twice. Pass your own when your job may run again:{ idempotencyKey: "launch:42" }. - Image generation is charged, so it is retried only after refusals that cost nothing.