Start building
Connect your SDK

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.

Shell
npm i @fuelpad/sdk

Set up

Make a secret key on the dashboard's Keys page and keep it on your server:

TypeScript
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

TypeScript
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

TypeScript
// 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

Shell
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

TypeScript
// 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

TypeScript
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.code is the API's stable error code; quote error.requestId to support.
  • Network errors, timeouts, 429 and 5xx are retried twice, waiting as Retry-After asks.
  • Every POST carries an Idempotency-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.