Skip to main content

Documentation Index

Fetch the complete documentation index at: https://blank.build/docs/llms.txt

Use this file to discover all available pages before exploring further.

Launch Tokens

For a normal integration, you only need this:
const result = await blank.launch.create(input, wallet);
Everything below is what’s actually happening when you call it, and the rules the worker enforces on the input.

The input

type LaunchCreateInput = {
  creator?: string;
  name: string;
  symbol: string;
  metadataUri: string;
  antiSnipeEnabled?: boolean;
  staking?: {
    shareBps: number;
  };
  creatorFeeSplit?: Array<{
    walletAddress: string;
    bps: number;
  }>;
  /** Optional. An identical retry replays the cached response. A concurrent retry returns 409. */
  idempotencyKey?: string;
};
What the worker checks:
  • creator defaults to the wallet that signs. API launches are attributed to whoever owns the API key, but the signed creator wallet is recorded on-chain as provenance.
  • name must be 32 bytes or less, NFKC-normalized, and free of zero-width / RTL / mixed-script characters. Reserved names like "Solana" or "Bitcoin" are rejected.
  • symbol must be 10 bytes or less, no spaces, and not a reserved ticker (SOL, USDC, BLNK).
  • metadataUri must be a compact ipfs:// or ar:// URI of 72 bytes or less. It must already resolve to public JSON with an image field before build. Gateway URLs (e.g. https://gateway.pinata.cloud/...) are rejected — see Metadata URI Rules.
  • creatorFeeSplit can have one to five unique wallets and must total exactly 10,000 bps (100%). 100 bps = 1%, so a 7,000 / 3,000 split is 70% / 30%.
  • staking.shareBps optionally enables staking in the launch bundle. Valid range: 100 to 10,000 bps, where 2,000 means 20% of the creator’s fee share routes to stakers.

Metadata must be public before build

Blank resolves metadata before it creates the transaction bundle. For automated launchers, treat this as part of your launch pipeline:
  1. Upload the image.
  2. Upload metadata JSON that points to that image.
  3. Poll a public gateway until the metadata URL returns HTTP 200 JSON with the expected image.
  4. Call blank.launch.create() with the canonical ipfs://... or ar://... URI, not the gateway URL.
If you call the SDK immediately after pinning metadata, the provider may have accepted the upload while the public gateway is still catching up. In that case build fails with LAUNCH_BUILD_METADATA_UNRESOLVABLE.

What the SDK actually does

When you call blank.launch.create(), it runs through four steps:
  1. Calls POST /api/v1/launch/build with your input.
  2. Gets back a server-built versioned (v0) Solana transaction bundle — sometimes one transaction, sometimes more.
  3. Asks your wallet to sign the bundle.
  4. Calls POST /api/v1/token/submit with the signed transactions and returns the result.
Build and submit are split into two HTTP calls because that’s how the on-chain flow works. From your code’s perspective, it’s still one user action: “create the token.”
A v0 transaction is just the modern Solana transaction format that supports address lookup tables. You don’t need to know the details — your wallet handles it.

What build returns under the hood

If you call /api/v1/launch/build directly, you’ll see:
  • launchId
  • mintAddress
  • dbcConfig
  • poolAddress
  • feeCollector
  • feeVault
  • feeSplitConfig
  • stakingPoolAddress (or null when staking was not enabled at launch)
  • lookupTable (or null)
  • submissionIntentId
  • payload.kind — currently "solana-v0-transaction-bundle"
  • payload.transactions — base64-encoded unsigned v0 transactions
  • payload.requiredUserSigner — the wallet that has to sign
  • expiresAt
The payload includes a recent blockhash, so it expires fast. You have about 60 seconds to build, sign, and submit before it goes stale. Don’t cache it; build right before you need it.

Idempotency (safe retries)

Pass an idempotencyKey (any unique-per-attempt string up to 200 bytes) and the worker will dedupe short-window build retries for you for 5 minutes. Useful when network blips make you unsure whether the original build call finished.
  • Same key, same body, original already finished → the cached response is replayed (HTTP 201). No new vanity mint is consumed.
  • Same key, original still in flight → returns 409 IDEMPOTENCY_KEY_IN_FLIGHT. Wait it out.
  • Same key, original failed → the lock is released and your retry proceeds normally.

Retrying after a failed submit

If your wallet has already signed but the relay step fails, or a Jito bundle is accepted but does not land before expiry, the SDK throws LaunchSubmissionFailedError. That error keeps the signed transactions and the submission intent ID, so you can retry without prompting the wallet again:
import { LaunchSubmissionFailedError } from "@blankdotbuild/sdk";

try {
  const launch = await blank.launch.create(input, wallet);
} catch (error) {
  if (error instanceof LaunchSubmissionFailedError) {
    await blank.launch.retrySubmit({
      submissionIntentId: error.submissionIntentId,
      signedTransactions: error.signedTransactions,
    });
  } else {
    throw error;
  }
}

A note on transports

Basic launches must go through a Jito bundle with bundleOnly: true. Jito bundles are atomic transaction groups designed to land together — this is what keeps a launch from getting partially executed. The SDK picks the right transport for you. The server will reject submissions that try to use transport: "auto" directly.

Submitting outside the SDK

You can technically take the signed transactions and broadcast them straight to an RPC node yourself. Blank still tracks launch state from the build record, the submission intent, the database, and on-chain reconciliation, so the launch will eventually show up correctly. But the SDK’s submit path is what gives you the signature back, observes the launch, and uses the right transport — there’s no real reason to bypass it.