@blankdotbuild/sdk
v4.0.2
Published
The official server-side TypeScript client for Blank API v2. Version 3 is a hard cutover to the production API: it provides typed resource modules, runtime response validation, bounded retries, durable idempotency keys, Problem Details errors, pagination
Readme
@blankdotbuild/sdk
The official server-side TypeScript client for Blank API v2. Version 3 is a hard cutover to the production API: it provides typed resource modules, runtime response validation, bounded retries, durable idempotency keys, Problem Details errors, pagination helpers, transaction-intent submission, and webhook signature verification.
Install
npm install @blankdotbuild/sdkNode.js 20 or newer is required. Blank API keys are server-side credentials and the SDK rejects configuring one in a browser runtime.
Quick start
import { BlankClient } from "@blankdotbuild/sdk";
const blank = new BlankClient({
apiKey: process.env.BLANK_API_KEY,
});
const token = await blank.tokens.get("TOKEN_MINT_ADDRESS");
console.log(token.data);
console.log(token.metadata.requestId);The default API origin is https://api.blank.build/api/v2. Override baseUrl only for a trusted staging or local Blank deployment.
Price predictions
const rounds = await blank.predictions.rounds("TOKEN_MINT_ADDRESS");
const round = rounds.data.data[0];
const prediction = await blank.predictions.create({
roundId: round.id,
walletAddress: process.env.BLANK_WALLET_ADDRESS!,
predictedPriceInSol: "0.00042",
});
console.log(prediction.data.id);Server integrations can also submit for an end user with a predictions:delegate key. Prepare an intent on the server, pass only its exact message to the user's wallet for UTF-8 Ed25519 signing, base58-encode the signature, and submit it from the server:
const intent = await blank.predictions.createDelegatedIntent({
roundId: round.id,
walletAddress: endUserWallet,
predictedPriceInSol: "0.00042",
});
const delegated = await blank.predictions.createDelegated({
intentId: intent.data.id,
signature: base58WalletSignature,
});The intent expires after five minutes or at round lock and can be consumed once. The API key remains server-side and never replaces the end user's wallet signature.
Mutations accept an optional idempotencyKey. If omitted, the SDK generates one and exposes it as result.metadata.idempotencyKey, so callers can persist it for audit and recovery.
Transaction intents
Write operations that require a wallet return a transaction intent. Sign the prepared transaction without changing its message, then submit it with the intent version:
const intent = await blank.transactionIntents.get("INTENT_ID");
const submitted = await blank.transactionIntents.submit(
intent.data.id,
{
signedTransaction: "BASE64_SIGNED_TRANSACTION",
version: intent.data.version,
},
{ idempotencyKey: "your-durable-idempotency-key" }
);Blank verifies the message, required signer, blockhash window, policy, and optimistic version before broadcast. Never sign a transaction your application has not independently inspected.
Errors, retries, and cancellation
BlankApiError exposes the stable API code, HTTP status, requestId, field errors, rate-limit metadata, retryAfterSeconds, and the mutation idempotencyKey. BlankNetworkError distinguishes caller aborts, timeouts, and network failures and also preserves that key so a caller can safely retry an uncertain mutation.
The SDK retries at most twice for network errors, timeouts, and 429, 502, 503, and 504. A mutation is retried only when it has an idempotency key. The default per-attempt timeout is 30 seconds. Automatic waits are capped at 30 seconds; longer Retry-After instructions are returned to the caller. Every request accepts an AbortSignal, timeout override, and retry override.
const controller = new AbortController();
const result = await blank.tokens.list(
{ limit: 50 },
{ signal: controller.signal, timeoutMs: 5_000, retries: 1 }
);Pagination
List methods return an opaque cursor. Bounded async iterators are available for high-volume traversal:
for await (const token of blank.tokens.iterate({}, { maxPages: 20 })) {
console.log(token.mintAddress);
}Webhook verification
Verify the exact raw request body before parsing JSON. During secret rotation, pass both the current and previous secret for the configured overlap window.
import { verifyWebhookSignature } from "@blankdotbuild/sdk";
const valid = await verifyWebhookSignature({
rawBody,
signatureHeader: request.headers.get("blank-signature") ?? "",
secret: process.env.BLANK_WEBHOOK_SECRET!,
previousSecret: process.env.BLANK_PREVIOUS_WEBHOOK_SECRET,
});Webhook payloads use CloudEvents 1.0 and stable, versioned event types. Return any 2xx response only after the event is durably accepted; Blank retries other outcomes with exponential backoff.
Full documentation: https://blank.build/docs/for-developers
