Node.js quickstart: create a Solana token in under 40 lines
This script does the whole flow with fetch and @solana/web3.js. Run it with Node 18 or newer as an ES module (.mjs).
Before you start
- An API key from the developer portal, in the environment variable
TOKENANVIL_KEY. - A dedicated wallet with at least 0.05 SOL, its secret key (base58) in
WALLET_SECRET_KEY. Use a wallet that holds only what automation needs. npm i @solana/web3.js bs58
The script
// npm i @solana/web3.js bs58
import { Connection, Keypair, Transaction } from "@solana/web3.js";
import bs58 from "bs58";
const API = "https://developers.tokenanvil.store/v1";
const headers = { Authorization: `Bearer ${process.env.TOKENANVIL_KEY}`, "Content-Type": "application/json" };
const wallet = Keypair.fromSecretKey(bs58.decode(process.env.WALLET_SECRET_KEY));
async function call(method, path, body) {
const res = await fetch(API + path, { method, headers, body: body ? JSON.stringify(body) : undefined });
const json = await res.json();
if (!res.ok) throw new Error(`${res.status} ${json.error?.code}: ${json.error?.message}`);
return json;
}
const meta = await call("POST", "/metadata", { name: "Demo Token", symbol: "DEMO", description: "Created with the API", imageUrl: "https://example.com/logo.png" });
const built = await call("POST", "/tokens", { payer: wallet.publicKey.toBase58(), name: "Demo Token", symbol: "DEMO", supply: "1000000", decimals: 9, revokeMint: true, metadataUri: meta.metadataUri });
const tx = Transaction.from(Buffer.from(built.transaction, "base64"));
tx.partialSign(wallet);
const connection = new Connection("https://api.mainnet-beta.solana.com", "confirmed");
const signature = await connection.sendRawTransaction(tx.serialize());
await connection.confirmTransaction(signature, "confirmed");
console.log("mint:", built.mint, "signature:", signature);
What to expect
The metadata call returns two URLs. The build call returns the new mint address and a base64 transaction that is valid for about a minute. After confirmTransaction resolves, the token exists and the full supply is in your wallet. A failed simulation returns an error before anything is built, so you do not pay for a doomed attempt.
Handling errors
Errors have a stable code (invalid_request, insufficient_funds, daily_limit, rate_limited and others) and, for validation, a fields object that names each problem. The reference lists them all. Retry only on 503 and network errors; fix the request for 400.
Next: sign safely and verify the result.