# GraveMint SDK — method reference



**`@solanadeads/gravemint`** · version **1.3.0** · install with `npm i @solanadeads/gravemint`

Signatures and types are generated from the published package. Explanatory prose is edited for clarity. For how to put them
together, start with the [GraveMint SDK guide](https://docs.deads.io/sdk/gravemint.md).



```ts
import { GraveMintClient } from "@solanadeads/gravemint";
const client = new GraveMintClient({ apiKey: "gm_pub_..." });
```

## Contents

- [`client.platform`](#client-platform) — 2 methods
- [`client.discovery`](#client-discovery) — 7 methods
- [`client.collections`](#client-collections) — 3 methods
- [`client.nfts`](#client-nfts) — 1 method
- [`client.bounty`](#client-bounty) — 2 methods
- [`client.codes`](#client-codes) — 1 method
- [`client.v1`](#client-v1) — 19 methods
- [`client.mint`](#client-mint) — 4 methods
- [Functions](#functions) — 11
- [Classes](#classes) — 12
- [Types](#types) — 68

## `client.platform`

> First-party only — not usable with a partner key. See [Legacy read API](https://docs.deads.io/sdk/gravemint.md#legacy-read-api).

### `platform.getCapabilities()`

GET /platform-capabilities

Public feature-flag snapshot — which chains are enabled, which optional
features (raffles, packs) the platform exposes.

```ts
getCapabilities(options?: RequestOptions): Promise<PlatformCapabilities>;
```

### `platform.getTokenPrices()`

GET /token-prices

USD pricing snapshot for supported chain natives. Returns a map keyed by
symbol — e.g. `{ SOL: 240, ETH: 0, POL: 0, SUI: 0 }`. The `sources` map
tells you which provider each price came from (or "unavailable").
Intended for display, not for settlement-grade pricing.

```ts
getTokenPrices(options?: RequestOptions): Promise<TokenPricesResponse>;
```

## `client.discovery`

> First-party only — not usable with a partner key. See [Legacy read API](https://docs.deads.io/sdk/gravemint.md#legacy-read-api).

### `discovery.getFeatured()`

GET /featured — `{success, collections: [...]}`

```ts
getFeatured(filters?: DiscoveryFilters, options?: RequestOptions): Promise<CollectionSummary[]>;
```

### `discovery.getLiveMints()`

GET /live-mints — `{success, mints: [...]}`

```ts
getLiveMints(filters?: DiscoveryFilters, options?: RequestOptions): Promise<CollectionSummary[]>;
```

### `discovery.getTrending()`

GET /trending — `{success, type, collections: [...]}`

```ts
getTrending(filters?: DiscoveryFilters, options?: RequestOptions): Promise<CollectionSummary[]>;
```

### `discovery.getUpcoming()`

GET /upcoming-mints — `{success, mints: [...]}`

```ts
getUpcoming(filters?: DiscoveryFilters, options?: RequestOptions): Promise<CollectionSummary[]>;
```

### `discovery.getRecentSoldouts()`

GET /recent-soldouts — `{collections: [...]}` (no success wrapper)

```ts
getRecentSoldouts(filters?: DiscoveryFilters, options?: RequestOptions): Promise<CollectionSummary[]>;
```

### `discovery.listCollections()`

GET /collections — `{success, collections: [...]}`

```ts
listCollections(params?: DiscoveryFilters & {
        offset?: number;
        status?: "active" | "ended" | "upcoming";
    }, options?: RequestOptions): Promise<CollectionSummary[]>;
```

### `discovery.searchCollections()`

GET /collections/search?q=... — `{success, collections: [...]}` (snake_case items).

Min query length 2 (server-enforced). Items returned use snake_case
(`short_id`, `total_supply`, `blockchain_network`) unlike the other
discovery feeds which use camelCase. We type this distinctly so the
compiler catches the mismatch.

```ts
searchCollections(query: string, params?: {
        limit?: number;
    }, options?: RequestOptions): Promise<CollectionSearchResult[]>;
```

## `client.collections`

> First-party only — not usable with a partner key. See [Legacy read API](https://docs.deads.io/sdk/gravemint.md#legacy-read-api).

### `collections.get()`

GET /collection/:identifier

Full collection record + stats + mint phases + server time. The response
is a discriminated union — when the collection isn't fully deployed yet
the server returns a pre-launch envelope (`status: 'coming_soon' |
'deploying' | 'maintenance'`) instead of the full record. Branch on
`('status' in result)` or check for the presence of `result.stats`.

```ts
get(identifier: CollectionIdentifier, options?: RequestOptions): Promise<CollectionResponse>;
```

### `collections.getGallery()`

GET /collection/:identifier/gallery

Paginated list of NFTs in the collection.

```ts
getGallery(identifier: CollectionIdentifier, params?: {
        limit?: number;
        offset?: number;
        mintedOnly?: boolean;
    }, options?: RequestOptions): Promise<RecentMint[]>;
```

### `collections.getRecentlyMinted()`

GET /collection/:identifier/recently-minted

Live mint activity. Returns minter wallets (publicly on-chain).

```ts
getRecentlyMinted(identifier: CollectionIdentifier, params?: {
        limit?: number;
    }, options?: RequestOptions): Promise<RecentMint[]>;
```

## `client.nfts`

> First-party only — not usable with a partner key. See [Legacy read API](https://docs.deads.io/sdk/gravemint.md#legacy-read-api).

### `nfts.get()`

GET /nft/:identifier

Single NFT record. Identifier is `mint_address` (Solana),
`contract:tokenId` (EVM), or numeric token id. UUIDs rejected.

```ts
get(identifier: NftIdentifier, options?: RequestOptions): Promise<RecentMint>;
```

## `client.bounty`

> First-party only — not usable with a partner key. See [Legacy read API](https://docs.deads.io/sdk/gravemint.md#legacy-read-api).

### `bounty.getSummary()`

```ts
getSummary(identifier: CollectionIdentifier, options?: RequestOptions): Promise<BountySummary>;
```

### `bounty.getPrizes()`

```ts
getPrizes(identifier: CollectionIdentifier, options?: RequestOptions): Promise<BountyPrizesResponse>;
```

## `client.codes`

> First-party only — not usable with a partner key. See [Legacy read API](https://docs.deads.io/sdk/gravemint.md#legacy-read-api).

### `codes.validate()`

POST /code/validate

Check whether a claim code is valid. Does NOT consume the code.

Note: this endpoint does NOT use the `{success:true}` envelope. The
response shape is `{valid: boolean, error?: string, ...}`.

```ts
validate(code: string, options?: RequestOptions): Promise<CodeValidationResult>;
```

## `client.v1`

> Works with a partner key.

The versioned contract: everything needed to BUILD a mint page.

### `v1.collection()`

Everything needed to render the drop.

```ts
collection(identifier: string): Promise<V1Collection>;
```

### `v1.eligibility()`

Checks whether a wallet meets a phase’s requirements, including NFT holdings and allowlists. The response keeps eligibility separate from the time window: also check `phase.hasStarted` and `phase.hasEnded` before enabling minting.

```ts
eligibility(collectionId: string, phaseId: string, walletAddress: string): Promise<V1Eligibility>;
```

### `v1.gallery()`

The drop's NFTs that can still be minted, paginated. Minted NFTs are
not included — use `allMinted()` for those. `limit` defaults to 100.

Scoped server-side to the collections your key covers, so this can only ever
return your own drop — a key issued for another collection gets a 403
`COLLECTION_NOT_IN_SCOPE`, not an empty list.

```ts
gallery(identifier: string, params?: {
        limit?: number;
        offset?: number;
    }): Promise<V1Gallery>;
```

### `v1.recentlyMinted()`

The live "just minted" feed for the drop — the same one gravemint.io renders.

```ts
recentlyMinted(identifier: string, params?: {
        limit?: number;
    }): Promise<V1RecentlyMinted>;
```

### `v1.bounty()`

Bounty summary for the drop, when it has one.

```ts
bounty(identifier: string): Promise<V1BountySummary>;
```

### `v1.bountyPrizes()`

The bounty's public prize table.

```ts
bountyPrizes(identifier: string): Promise<V1BountyPrizes>;
```

### `v1.walletMints()`

Returns minted and remaining counts per phase, including bonus mints such as BOGO and bounty mints. Use this response for wallet counts; eligibility uses separate allocation rules.

```ts
walletMints(collectionId: string, walletAddress: string): Promise<V1WalletMints>;
```

### `v1.claimCodes()`

Does this drop use claim codes, and of what kind?

```ts
claimCodes(collectionId: string): Promise<V1ClaimCodes>;
```

### `v1.claimCodeBenefits()`

What a specific wallet is already entitled to from codes it has redeemed.

```ts
claimCodeBenefits(collectionId: string, walletAddress: string, params?: {
        phaseId?: string;
        blockchain?: string;
        packTierId?: string;
    }): Promise<V1ClaimCodeBenefits>;
```

### `v1.validateClaimCode()`

Check a code against THIS drop.

Scoped on purpose. The code is resolved and its own collection compared with the
one you name, and a code belonging to another drop answers exactly as an unknown
code does — so this can never be used to discover that a code exists elsewhere.

```ts
validateClaimCode(collectionId: string, code: string): Promise<V1ClaimCodeCheck>;
```

### `v1.tokenPrices()`

Platform token prices — what an SPL-priced drop is worth in USD. Global, no drop.

```ts
tokenPrices(): Promise<V1TokenPrices>;
```

### `v1.peggedPrice()`

The resolved amount for a USD- or native-pegged phase, on its own — e.g. to refresh
a live peg without re-reading the whole drop. `phase.priceDisplay` on the collection
response already resolves pegs for display. (v1 phases carry no raw `price` field.)

```ts
peggedPrice(phaseId: string): Promise<V1PeggedPrice>;
```

### `v1.dutchPrice()`

The live price of a dynamic Dutch phase, which moves with time.

```ts
dutchPrice(phaseId: string): Promise<V1DutchPrice>;
```

### `v1.availability()`

Supply counts for the drop (see `V1Availability`): fine for a progress bar, not for
deciding a drop is sold out. `prepare` is what actually allocates supply.

```ts
availability(collectionId: string): Promise<V1Availability>;
```

### `v1.traits()`

Trait names and values, for filtering a gallery.

```ts
traits(identifier: string): Promise<V1Traits>;
```

### `v1.allMinted()`

Returns one page of minted items. `limit` defaults to 20 and is capped at 100. Increment `offset` until `hasMore` is false. Use `newest` or `oldest` for a full paginated history; `popular` ranks within each page.

```ts
allMinted(identifier: string, params?: {
        limit?: number;
        offset?: number;
        sort?: "newest" | "oldest" | "popular";
        search?: string;
    }): Promise<V1AllMinted>;
```

### `v1.topHolders()`

Largest holders — social proof for a mint page.

```ts
topHolders(identifier: string): Promise<V1TopHolders>;
```

### `v1.topMinters()`

Who minted the most.

```ts
topMinters(identifier: string): Promise<V1TopMinters>;
```

### `v1.version()`

What the API is; useful for degrading deliberately rather than on a 404.

```ts
version(): Promise<{
        version: string;
        stability: string;
        docs: string;
    }>;
```

## `client.mint`

> Works with a partner key.

prepare -> sign -> execute. You sign; GraveMint broadcasts.

### `mint.prepare()`

Ask GraveMint to price, check eligibility, reserve supply and build the transaction.

```ts
prepare(input: PrepareMintInput): Promise<PreparedMint>;
```

### `mint.execute()`

Submits the signed transaction through GraveMint. The default timeout is 130 seconds; a configured client-wide `timeoutMs` takes precedence. Execute is not retried automatically by default. An uncertain result requires checking the existing mint before submitting again. Override `options.maxRetries` only with application-level outcome handling.

```ts
execute(input: {
        sessionId: string;
        signedTransaction: string;
    }, options?: RequestOptions): Promise<V1ExecuteResult>;
```

### `mint.executeBatch()`

Hand back SEVERAL signed transactions at once.

Required for any quantity above 1: every Solana standard mints exactly one
NFT per transaction (`maxPerTx = 1` for mpl-core, legacy and compressed), so
a prepare for N returns N transactions and N sessions.

```ts
executeBatch(entries: Array<{
        sessionId: string;
        signedTransaction: string;
    }>, options?: RequestOptions): Promise<V1ExecuteBatchResult>;
```

### `mint.mint()`

Coordinates preparation, signing and execution. Check `capabilities.supportedBySurface` first and offer `mintUrl` for collections outside the core flow. Throws if preparation returns no transaction to sign.

```ts
mint(input: PrepareMintInput & {
        signer: TransactionSigner;
    }, 
    /** Applied to the EXECUTE call (timeout, signal). Prepare uses the client defaults. */
    executeOptionsOverride?: RequestOptions): Promise<MintResult>;
```

## Functions

### `fromHttpStatus`

Map an HTTP status to the right error class. Used internally by the HTTP
transport. The `body` is the parsed JSON response if available.

```ts
export declare function fromHttpStatus(status: number, message: string, body: unknown, requestId?: string): GraveMintError;
```

### `isBatchMintResult`

True when `mint()` minted more than one NFT and answered with the batch shape.

```ts
export declare function isBatchMintResult(result: MintResult): result is V1MintBatchOutcome;
```

### `isUuid`

Input validation. Catches obvious bad inputs client-side to save round-trips
and rate-limit budget. Server-side validation is still authoritative.

Returns true if the string looks like a UUID.

```ts
export declare function isUuid(s: string): boolean;
```

### `looksLikeAddress`

Returns true if the string looks like a valid on-chain address (any chain).

```ts
export declare function looksLikeAddress(s: string): boolean;
```

### `normalizeClaimCode`

Normalize a claim code (trim, then upper-case), rejecting only what can never be a code: a
non-string, or something under 4 or over 1024 UTF-16 code units after trimming and upper-casing.
Format-level only; existence is the server's answer.

Deliberately permissive. This used to allow only 6-40 characters of A-Z, 0-9
and '-', and so rejected real codes before the server was ever asked: imported codes of 4-5 or
41-64 characters, codes with `_` or `.`, and generated codes whose prefix has a space or an
accented letter. Seven such codes are live (measured 2026-09-23). A client check stricter than
the server can only produce false rejections.

NOTE for senders: the server upper-cases the code itself. `codes.validate()` sends the TRIMMED
code rather than this upper-cased form, because `toUpperCase()` differs across JS engines'
Unicode versions for a handful of letters, and the server's answer must not depend on the
caller's runtime.

```ts
export declare function normalizeClaimCode(code: unknown): string;
```

### `sanitize`

Response sanitization. Removes PII and internal identifiers before returning
data to SDK consumers.

Policy ("standard"):
  - STRIP: emails, IP addresses, push subscriptions, fingerprints, internal UUIDs
    (any field literally named `id` at any depth, plus known UUID-shaped fields)
  - KEEP: wallet addresses (publicly on-chain), display names, mint addresses,
    short_ids, content URLs.

The sanitizer is conservative — when in doubt, it strips. Consumers who need
the raw response can set `client.options.sanitize = false` per-request, but
doing so re-exposes UUIDs and is documented as unsafe for public callers.

Returns a deep-cleaned copy of the input. Does not mutate. Safe to call on
arbitrary JSON-shaped data (arrays, objects, primitives, null).

```ts
export declare function sanitize<T = unknown>(value: T): T;
```

### `validateCollectionIdentifier`

Validate a collection identifier. Accepts a short_id or an on-chain address.
Explicitly rejects UUIDs — the SDK does not expose internal IDs.

Throws `ValidationError` on bad input.

```ts
export declare function validateCollectionIdentifier(id: unknown): string;
```

### `validateLimit`

Validate a pagination `limit` against a max. Returns the clamped value.

```ts
export declare function validateLimit(limit: unknown, max: number, fallback: number): number;
```

### `validateNftIdentifier`

Validate an NFT identifier. Accepts a mint_address, a contract:tokenId pair,
or a numeric token ID. Rejects UUIDs.

```ts
export declare function validateNftIdentifier(id: unknown): string;
```

### `validateOffset`

Validate an offset.

```ts
export declare function validateOffset(offset: unknown): number;
```

### `validateWalletAddress`

Validate a wallet address. Returns the input unchanged on success.

```ts
export declare function validateWalletAddress(addr: unknown): string;
```

## Classes

### `AuthError`

Server returned 401 / 403 — the request was refused. NOT only a key or origin
problem: on v1 a 403 is also a held or blocked wallet, a banned asset, a missing
key scope or a key class used on the wrong network. Branch on `code`, not on the
class.

```ts
export declare class AuthError extends GraveMintError {
}
```

### `ConfigError`

Configuration error — bad apiKey, missing baseUrl, invalid options.

```ts
export declare class ConfigError extends GraveMintError {
}
```

### `GraveMintError`

GraveMint SDK error hierarchy.

All errors thrown by the SDK extend `GraveMintError`. Catch this base class
to handle any SDK failure; catch a subclass to react to a specific failure
mode (rate limit, auth, bad input, etc.).

```ts
export declare class GraveMintError extends Error {
    readonly name: string;
    readonly status?: number | undefined;
    readonly code?: string | undefined;
    readonly requestId?: string | undefined;
    /**
     * The server's parsed error body, when it sent JSON. This is where a code's
     * documented extra fields live — e.g. `reason` / `blockedUntil` / `permanent` on
     * `WALLET_BLOCKED`, `retryAfter` on `COLLECTION_RATE_LIMITED`.
     * RAW and unsanitized (error bodies are not run through the response sanitizer), and
     * its shape varies by route — read the documented field you need, do not forward it
     * whole. Undefined for errors raised on the client.
     */
    readonly details?: unknown;
    constructor(message: string, opts?: {
        status?: number;
        code?: string;
        requestId?: string;
        details?: unknown;
        cause?: unknown;
    });
}
```

### `HttpClient`

```ts
export declare class HttpClient {
    private readonly baseUrl;
    private readonly apiKey;
    private readonly timeoutMs;
    private readonly maxRetries;
    /** The client-wide timeout the CALLER set, or undefined when it is the default. */
    readonly configuredTimeoutMs: number | undefined;
    private readonly sanitize;
    private readonly fetchImpl;
    private readonly clientId;
    private readonly limiter;
    constructor(opts: HttpClientOptions);
    get<T>(path: string, options?: RequestOptions): Promise<T>;
    post<T>(path: string, body: unknown, options?: RequestOptions): Promise<T>;
    private request;
}
```

### `MintOutcomeUnknownError`

`mint()` submitted signed transactions but could not confirm the outcome. This can follow a timeout, connection loss, server error or an already-processing response. The mint may still complete. Retain `sessionIds`, display the message and check the wallet before starting another mint. This SDK error uses `code: "OUTCOME_UNKNOWN"`.

```ts
export declare class MintOutcomeUnknownError extends GraveMintError {
    readonly sessionIds: string[];
    constructor(sessionIds: string[], opts?: {
        cause?: unknown;
        requestId?: string;
    });
}
```

### `NetworkError`

Network failure — DNS, TCP, TLS, fetch timeout.

```ts
export declare class NetworkError extends GraveMintError {
}
```

### `NotFoundError`

Server returned 404 — resource does not exist.

```ts
export declare class NotFoundError extends GraveMintError {
}
```

### `RateLimitError`

Server returned 429 — rate limit hit. `retryAfterMs` is the server-suggested wait.

```ts
export declare class RateLimitError extends GraveMintError {
    readonly retryAfterMs: number;
    constructor(message: string, retryAfterMs: number, opts?: {
        status?: number;
        code?: string;
        requestId?: string;
        details?: unknown;
    });
}
```

### `ServerError`

Server returned 5xx after exhausting retries.

```ts
export declare class ServerError extends GraveMintError {
}
```

### `TimeoutError`

Request was aborted (client-side timeout or external AbortSignal).

```ts
export declare class TimeoutError extends GraveMintError {
}
```

### `TokenBucketRateLimiter`

```ts
export declare class TokenBucketRateLimiter {
    private tokens;
    private lastRefill;
    private readonly refillRate;
    private readonly capacity;
    private readonly queue;
    /** The ONE pending wake-up while anyone is queued. */
    private timer;
    constructor(config: RateLimitConfig);
    /**
     * Acquire one token. Resolves immediately if one is available and nobody is waiting, otherwise
     * queues (first come, first served). Honors `signal` — aborting rejects the wait.
     *
     *: this used to arm one timer per waiter, and a woken waiter that found no token
     * re-queued itself WITHOUT a timer — once the armed timers had fired, everyone still queued hung
     * forever (12 concurrent calls at the defaults: 11 resolved). Now a single drain loop owns the
     * queue: one timer while anyone waits, each tick hands out every available token in order, then
     * re-arms for the next.
     */
    acquire(signal?: AbortSignal): Promise<void>;
    /** Arm the single wake-up for the time the next token needs, if anyone is waiting. */
    private schedule;
    /** Hand every available token to the queue in order, then re-arm for whoever is left. */
    private drain;
    private refill;
}
```

### `ValidationError`

Input validation error — bad address, malformed identifier, out-of-range limit.

```ts
export declare class ValidationError extends GraveMintError {
}
```

## Types

### `Blockchain`

Public-facing types for the GraveMint SDK.

```ts
export type Blockchain = "solana-mainnet" | "solana-devnet" | "ethereum-mainnet" | "polygon-mainnet" | "base-mainnet" | "arbitrum-mainnet" | "optimism-mainnet" | "bsc-mainnet" | "avalanche-mainnet" | "apechain-mainnet" | "abstract-mainnet" | "cronos-mainnet" | "berachain-mainnet" | "sui-mainnet" | "sui-testnet" | string;
```

### `BountyPrize`

```ts
export interface BountyPrize {
    kind: "milestone_group" | "individual";
    name: string;
    bounties: Array<{
        mint_count?: number;
        name: string;
        nft?: {
            mint_address: string | null;
            name: string | null;
            image_url: string | null;
        };
        token?: {
            symbol: string;
            amount: string | number;
            decimals: number;
        };
        grant?: string;
        status: "open" | "claimed" | "expired";
        winner_wallet?: string | null;
        claimed_at?: string | null;
    }>;
}
```

### `BountyPrizesResponse`

```ts
export interface BountyPrizesResponse {
    enabled: boolean;
    show_occurrence?: boolean;
    show_winners?: boolean;
    sections?: BountyPrize[];
}
```

### `BountySummary`

```ts
export interface BountySummary {
    enabled: boolean;
    total_milestones?: number;
    triggered?: number;
    total_funded_usd?: number;
    next_threshold?: number | null;
    [key: string]: unknown;
}
```

### `CodeValidationResult`

`/code/validate` does NOT use the {success:true} envelope.

```ts
export interface CodeValidationResult {
    valid: boolean;
    /** Server-side reason string when valid=false. */
    error?: string;
    /** `external` and `nft_redemption` are real grant types the server returns. */
    grantType?: "whitelist" | "free_mint" | "discount" | "external" | "nft_redemption";
    /** Number of mints the code grants, when it grants any. */
    mintAllocation?: number | null;
    /** Percentage discount — the field the server actually sends. */
    discountPercentage?: number | null;
    /** Fixed-amount discount, in the drop's currency. */
    discountFixed?: number | null;
    usesRemaining?: number | null;
    /**
     * @deprecated The server has never sent this name — it sends `discountPercentage`.
     * Always undefined; kept so existing code still compiles.
     */
    discountPercent?: number;
    collectionShortId?: string | null;
    collectionAddress?: string | null;
    [key: string]: unknown;
}
```

### `CollectionDetail`

```ts
export interface CollectionDetail {
    /** Short, URL-safe public ID (e.g. "deads"). Preferred identifier. */
    shortId: string;
    name: string;
    symbol: string | null;
    bio: string | null;
    description: string | null;
    image: string | null;
    imageFocalY: number;
    bannerImage: string | null;
    bannerFocalY: number;
    externalUrl: string | null;
    blockchain: Blockchain;
    collectionAddress: string | null;
    contractAddress: string | null;
    nftStandard: "mpl-core" | "legacy" | "compressed" | "erc721" | "erc1155" | string;
    contentType: "image" | "audio" | "video" | string;
    enableGalleryMode: boolean;
    allowNftSelection: boolean;
    editionType: "unique" | "limited" | "limited_edition" | string;
    maxEditionSupply: number | null;
    allowImageDownload: boolean;
    showTraitRarity: boolean;
    twitter: string | null;
    discord: string | null;
    telegram: string | null;
    creatorWallet: string | null;
    twitterVerified: boolean;
    discordVerified: boolean;
    creatorVerified: boolean;
    royaltyPercentage: number;
    promoVideoUrl: string | null;
    isGenerative: boolean;
    enableDelayedReveal: boolean;
    isRevealed: boolean;
    roadmap: unknown;
    affiliateEnabled: boolean;
    mintReplaysEnabled: boolean;
    [key: string]: unknown;
}
```

### `CollectionDetailResponse`

```ts
export interface CollectionDetailResponse {
    collection: CollectionDetail;
    stats: CollectionStats;
    mintStatus: "upcoming" | "live" | "paused" | "ended" | "sold_out" | string;
    countdown: unknown;
    phases: {
        active: Phase[];
        upcoming: Phase[];
        all: Phase[];
    };
    serverTime: string;
}
```

### `CollectionIdentifier`

```ts
export type CollectionIdentifier = string;
```

### `CollectionPreLaunchResponse`

Pre-launch / maintenance variants returned by the same endpoint when the
collection is not yet fully deployed. The SDK type for `getCollection`
unions these so callers can branch on `status`.

```ts
export interface CollectionPreLaunchResponse {
    status: "coming_soon" | "deploying" | "maintenance";
    message: string;
    collection: {
        shortId?: string;
        name: string;
        image: string | null;
        blockchain: Blockchain;
        description?: string | null;
        totalSupply?: number;
        mintedCount?: number;
    };
    /** present only when status === 'coming_soon' */
    raffles?: Array<{
        name: string;
        status: string;
        winnerCount: number;
        registrationStart: string;
        registrationEnd: string;
    }>;
    hasClaimCodes?: boolean;
    hasWhitelistCodes?: boolean;
}
```

### `CollectionResponse`

```ts
export type CollectionResponse = CollectionDetailResponse | CollectionPreLaunchResponse;
```

### `CollectionSearchResult`

`/collections/search` returns snake_case unlike the camelCase feeds.

```ts
export interface CollectionSearchResult {
    short_id: string;
    name: string;
    symbol: string | null;
    image: string | null;
    image_url: string | null;
    collection_address: string | null;
    contract_address: string | null;
    blockchain_network: Blockchain;
    total_supply: number;
    minted_count: number;
}
```

### `CollectionStats`

```ts
export interface CollectionStats {
    totalSupply: number;
    mintedCount: number;
    burnedCount: number;
    availableCount: number | null;
    percentMinted: number;
}
```

### `CollectionSummary`

Discovery-feed summary (camelCase). Used by /featured, /trending, /live-mints, /upcoming-mints, /recent-soldouts.

```ts
export interface CollectionSummary {
    shortId: string;
    name: string;
    symbol: string | null;
    bio?: string | null;
    description?: string | null;
    image: string | null;
    imageCropPosition?: string;
    imageFocalY?: number;
    bannerImage?: string | null;
    bannerFocalY?: number;
    blockchain: Blockchain;
    collectionAddress?: string | null;
    contractAddress?: string | null;
    isGenerative?: boolean;
    promoVideoUrl?: string | null;
    verified?: boolean;
    socialVerified?: boolean;
    stats: {
        totalSupply: number;
        mintedCount: number;
        burnedCount?: number;
        availableCount?: number;
        percentMinted?: number;
        totalVolume?: number;
        floorPrice?: number;
        mintPrice?: number;
        mintCurrency?: string;
        isSoldOut?: boolean;
    };
    badges?: {
        hasBounties?: boolean;
        hasAffiliates?: boolean;
    };
    trending?: {
        rank?: number;
        mints24h?: number;
        mints7d?: number;
        mints30d?: number;
        volume24h?: number;
    };
    /** Present on /recent-soldouts */
    deployedAt?: string;
    firstMintedAt?: string;
    effectiveSoldOutAt?: string;
    soldOutAt?: string;
    selloutSeconds?: number;
    selloutLabel?: string;
    /** Present on /upcoming-mints */
    phase?: {
        name: string;
        type: string;
        price: number;
        currency: string;
        paymentToken: unknown;
        [k: string]: unknown;
    };
}
```

### `DiscoveryFilters`

```ts
export interface DiscoveryFilters {
    /** Limit results. Capped at 100. Default 20. */
    limit?: number;
    /** Filter by blockchain. Server ignores unknown values. */
    blockchain?: Blockchain;
}
```

### `GraveMintClientOptions`

```ts
export interface GraveMintClientOptions {
    /**
     * API key issued by GraveMint. Sent on every request as `X-API-Key`.
     * Required — even browser-side, the server enforces origin + key.
     */
    apiKey: string;
    /**
     * Override the API base URL. Default: production.
     * The public router is mounted at `/gravemint/public`; if you point at a
     * different host, keep the same path suffix.
     */
    baseUrl?: string;
    /**
     * Override the base URL for the versioned contract (`gm.v1`, `gm.mint`).
     *
     * You only need this when routing through your own proxy, or when `baseUrl`
     * points somewhere whose shape we cannot infer. If you set `baseUrl` to a
     * host ending in `/public`, this is derived for you by swapping the suffix.
     * If it ends in anything else we do NOT guess — the constructor throws,
     * because a wrong base on the mint path is a 404 discovered by a collector
     * mid-transaction rather than by you at startup.
     */
    v1BaseUrl?: string;
    /** Per-request timeout (ms). Default 30_000. */
    timeoutMs?: number;
    /** Max retry attempts on 429 / 5xx / network. Default 3. */
    maxRetries?: number;
    /**
     * Strip PII / internal UUIDs from responses. Default true.
     * Setting `false` re-exposes internal identifiers — not recommended for
     * production callers.
     */
    sanitize?: boolean;
    /**
     * Client-side rate limit. Pass `null` to disable. Default 5 RPS sustained,
     * 10 RPS burst (300/min) — below the server's published 600 reads/min/IP floor
     * (README "Rate limits"). Mints have their own, lower per-key budget.
     */
    rateLimit?: RateLimitConfig | null;
    /**
     * Custom fetch implementation. Defaults to `globalThis.fetch` (Node 18+,
     * browsers, Bun, Deno). On older Node, pass `undici.fetch` or `node-fetch`.
     */
    fetch?: typeof fetch;
}
```

### `HttpClientOptions`

```ts
export interface HttpClientOptions {
    baseUrl: string;
    apiKey: string;
    /** Default timeout per request in milliseconds. Default 30s. */
    timeoutMs?: number;
    /** Max retry attempts on 429 / 5xx / network. Default 3. */
    maxRetries?: number;
    /** Sanitize responses (strip PII / UUIDs). Default true. */
    sanitize?: boolean;
    /** Client-side rate limit. Pass `null` to disable. Default {requestsPerSecond:5,burst:10}. */
    rateLimit?: RateLimitConfig | null;
    /** Custom fetch impl. Defaults to globalThis.fetch. */
    fetch?: typeof fetch;
    /** SDK version, sent as `x-gm-client`. Set by index.ts. */
    sdkVersion?: string;
}
```

### `MintResult`

`mint()`: a single result for quantity 1, a batch outcome (with `results`) above that.

```ts
export type MintResult = V1ExecuteResult | V1MintBatchOutcome;
```

### `NftIdentifier`

```ts
export type NftIdentifier = string;
```

### `Phase`

```ts
export interface Phase {
    name: string;
    type: "public" | "whitelist" | "presale" | "dutch_auction" | "dynamic_dutch" | string;
    status: "active" | "upcoming" | "ended";
    price: number;
    priceCurrency?: string | null;
    paymentTokenSymbol?: string | null;
    paymentTokenAddress?: string | null;
    paymentTokenDecimals?: number | null;
    startDate: string;
    endDate: string | null;
    maxPerWallet?: number | null;
    maxPerTransaction?: number | null;
    globalMintLimit?: number | null;
    timeUntilStart?: number | null;
    timeUntilEnd?: number | null;
    [key: string]: unknown;
}
```

### `PlatformCapabilities`

```ts
export interface PlatformCapabilities {
    solana?: {
        mplCore: boolean;
        legacy: boolean;
        compressed: boolean;
    };
    evm?: {
        erc721: boolean;
        erc1155: boolean;
    };
    sui?: {
        enabled: boolean;
        mainnet: boolean;
        testnet: boolean;
        editions: boolean;
    };
    features?: Record<string, boolean>;
    raffles?: {
        twitterRequirements: boolean;
        maxActiveRaffles: number;
    };
    enabledChains?: Record<string, boolean>;
    [key: string]: unknown;
}
```

### `PlatformSetting`

```ts
export interface PlatformSetting {
    setting_key: string;
    setting_value: unknown;
    is_public: boolean;
}
```

### `PreparedMint`

Response from `/v1/prepare-mint`. v1 returns `transactions[]` and `sessions[]`, including for quantity one. Use `sessions[0].sessionId` for the first transaction. The optional top-level `sessionId` supports legacy proxy responses.

```ts
export interface PreparedMint {
    success: boolean;
    /** Legacy single-shape only. On v1 this is undefined — use `sessions[0]`. */
    sessionId?: string;
    sessions?: Array<{
        sessionId: string;
        nftIds: string[];
        nftCount: number;
    }>;
    /** What was asked for. Compare with `totalQuantity`: see `quantityAdjusted`. */
    requestedQuantity?: number;
    /**
     * TRUE when fewer NFTs were prepared than requested (a wallet or phase limit, or supply).
     * Tell the collector — they are about to sign for fewer than they asked for.
     */
    quantityAdjusted?: boolean;
    /** Why, in a sentence, when the reason is a user-facing limit. */
    adjustmentReason?: string | null;
    /** Session lifetime in ms — use this for a countdown (clock-skew safe), not `expiresAt`. */
    expiresInMs?: number;
    transactions?: Array<{
        transaction?: string | null;
        isVersionedTransaction?: boolean;
        nftCount?: number;
    }>;
    totalQuantity?: number;
    /**
     * The AUTHORITATIVE price breakdown. This — not `priceDisplay` — is what the
     * collector actually pays. `priceDisplay` is for rendering the phase before a
     * mint is requested; the real figure only exists once GraveMint has run the
     * full cascade and reserved what the price depends on.
     */
    pricing?: Record<string, unknown>;
    bogo?: Record<string, unknown> | null;
    /** The session expires. Do not hold a signature and submit it later. */
    expiresAt?: string;
    chainType?: string;
}
```

### `PrepareMintInput`

```ts
export interface PrepareMintInput {
    /**
     * The drop to mint from: its UUID (`drop.collection.id`), `shortId`, or on-chain address. A
     * non-UUID is resolved within your key's own drops only.
     */
    collectionId: string;
    phaseId: string;
    quantity: number;
    walletAddress: string;
    /** Referral attribution. Validated server-side; ignored if the drop has none. */
    affiliateCode?: string | null;
    /**
     * The connected wallet's display name, e.g. `wallet.adapter.name` ("Phantom", "Solflare").
     * Analytics only: it fills the creator's wallet breakdown, which otherwise reads "Unknown"
     * for every mint from your site. Invalid values are dropped server-side.
     */
    walletProvider?: string | null;
}
```

### `PriceDisplay`

The four display-price variants returned by GraveMint’s price resolver.

```ts
export type PriceDisplay = {
    kind: "amount";
    amount: number;
    currency: string;
    isFree: boolean;
    approximate?: boolean;
} | {
    kind: "range";
    min: number;
    max: number;
    currency: string;
} | {
    kind: "hidden";
} | {
    kind: "unknown";
};
```

### `RateLimitConfig`

Client-side rate limiter (token bucket).

Why this exists: the server enforces its own limits (~80 reads/min/IP by
default) and returns 429 on overage. Hitting 429s wastes round-trips and
triggers bot-detection penalties. The SDK's client-side limiter keeps callers
under a configurable ceiling and serializes overage requests into a queue
rather than firing them off and getting blocked.

Configurable via `GraveMintClientOptions.rateLimit`:
  { requestsPerSecond: 5, burst: 10 }   // 5 RPS sustained, 10 RPS short burst

Setting `rateLimit: null` disables the client-side limiter (server still
enforces). Default: { requestsPerSecond: 5, burst: 10 }.

```ts
export interface RateLimitConfig {
    /** Sustained request rate per second. */
    requestsPerSecond: number;
    /** Max burst — tokens accumulated when idle. */
    burst: number;
}
```

### `RecentMint`

```ts
export interface RecentMint {
    tokenId: number | null;
    mintAddress: string | null;
    name: string | null;
    image: string | null;
    previewImage: string | null;
    fullImageUrl: string | null;
    generationStatus: string | null;
    ownerWallet: string | null;
    mintedAt: string;
    isRevealed: boolean;
    attributes: Array<{
        trait_type: string;
        value: string | number;
    }>;
    editionNumber: number | null;
    maxEditionSupply: number | null;
    isMasterEdition: boolean;
    currentEditionSupply?: number;
}
```

### `RequestOptions`

```ts
export interface RequestOptions {
    /** Per-request timeout override (ms). */
    timeoutMs?: number;
    /**
     * Per-request retry override. `execute` uses 0: re-POSTing signed transactions after an
     * ambiguous failure makes the server answer ALREADY_PROCESSING / ALREADY_COMPLETED /
     * SESSION_NOT_FOUND, which read as definite failures and hide that the first attempt
     * may have landed.
     */
    maxRetries?: number;
    /** Per-request signal for cancellation. Combined with timeout signal. */
    signal?: AbortSignal;
    /** Override sanitization for this request only. */
    sanitize?: boolean;
    /** Query-string params (values stringified). Undefined/null entries are skipped. */
    query?: Record<string, string | number | boolean | undefined | null>;
    /** JSON body for POST. */
    body?: unknown;
}
```

### `TokenPricesResponse`

```ts
export interface TokenPricesResponse {
    /** Map of native-chain symbol → USD price. e.g. { SOL: 240, ETH: 0, POL: 0, SUI: 0 }. */
    prices: Record<string, number>;
    /** Per-symbol source (e.g. "coingecko", "jupiter", "unavailable"). */
    sources: Record<string, string>;
    /** ms epoch when the snapshot was taken server-side. */
    timestamp: number;
    /** Server-side cache TTL in seconds. */
    cacheTTL: number;
}
```

### `TransactionSigner`

Anything that can sign a base64 transaction and hand back a base64 transaction.

Deliberately the narrowest possible surface: the less this SDK knows about your
wallet, the fewer ways it can break when you change it.

```ts
export interface TransactionSigner {
    signTransaction(base64Transaction: string): Promise<string>;
    /**
     * Optional. When present it is used for multi-transaction mints, so the
     * collector approves ONCE instead of N times. `@solana/wallet-adapter`
     * exposes this; a signer without it still works, one prompt per NFT.
     */
    signAllTransactions?(base64Transactions: string[]): Promise<string[]>;
}
```

### `V1AllMinted`

`allMinted()` — one page. Keep requesting with `offset` until `hasMore` is false.

```ts
export interface V1AllMinted {
    success: true;
    nfts: V1MintedItem[];
    /** Matching minted items in the whole drop. */
    total: number;
    hasMore: boolean;
    offset: number;
    /** The page size actually applied (the server caps it at 100). */
    limit: number;
    collection: {
        id: string;
        shortId: string | null;
        name: string | null;
        twitterHandle: string | null;
    };
    allowImageDownload: boolean;
}
```

### `V1Availability`

`availability()` — read fresh, the same counts as `getCollection().stats`. `available` is
`total - minted`; `minted` includes `burned` (a burned NFT was minted). An NFT held by a mint
still in progress counts as available until that mint completes, so `available` can briefly
read high: use it for a progress bar, and let `prepare` decide whether supply remains.
`available` is `null` for an open-ended generative drop, which has no fixed supply.
`percentMinted` is 0-100.

```ts
export interface V1Availability {
    success: true;
    collectionId: string;
    stats: {
        total: number;
        minted: number;
        burned: number;
        available: number | null;
        percentMinted: number;
    };
}
```

### `V1BatchTransactionResult`

One transaction's outcome inside a batch. `success: false` carries `error` (a sentence)
and usually `errorCode`. `pending: true` means it may still land — check the wallet,
do not retry. A success carries the minted NFTs under `minted` (an array here, unlike
the single-transaction answer, where `minted` is a count).

```ts
export interface V1BatchTransactionResult {
    sessionId: string;
    success: boolean;
    error?: string | null;
    errorCode?: string;
    pending?: boolean;
    recovered?: boolean;
    signature?: string;
    mintedCount?: number;
    minted?: V1MintedNft[];
    [k: string]: unknown;
}
```

### `V1BountyInventoryItem`

```ts
export interface V1BountyInventoryItem {
    id: string;
    name: string | null;
    image_url: string | null;
    mint_address: string | null;
    state: "unassigned" | "assigned" | "claimed";
    claimed_winner?: string | null;
    claimed_at?: string | null;
}
```

### `V1BountyItem`

One bounty in the prize table. Which of `nft` / `grant` / `token` is set depends on `bounty_type`.

```ts
export interface V1BountyItem {
    id: string;
    name: string | null;
    description: string | null;
    bounty_type: string | null;
    is_claimed: boolean;
    /** A shortened wallet, and only when the creator shows winners. */
    claimed_winner: string | null;
    claimed_at: string | null;
    nft?: {
        name: string | null;
        image_url: string | null;
        mint_address: string | null;
    };
    grant?: {
        label: string;
    };
    /** `amount` is in the token's smallest unit; null when the creator left it unset. */
    token?: {
        symbol: string | null;
        amount: number | null;
        decimals: number;
    };
    trigger?: {
        mint_count: number | null;
        starts_at: string | null;
    };
}
```

### `V1BountyPoolSection`

A recurring prize pool. `weight_pct` is the chance of each entry per draw.

```ts
export interface V1BountyPoolSection {
    id: string;
    name: string | null;
    description: string | null;
    mode: "recurring_pool";
    recur_every_n_mints: number | null;
    recur_max_fires: number | null;
    recur_fires_count: number;
    counter_starts_at: string | null;
    entries: Array<{
        reward_type: string;
        weight_bps: number;
        weight_pct: number;
        payout_amount: number | null;
        token_symbol: string | null;
        token_decimals: number | null;
        nft_pool_label: string | null;
        display_label: string | null;
        display_image_url: string | null;
    }>;
}
```

### `V1BountyPrizes`

`bountyPrizes()`. `enabled: false` when the creator does not show the prize table.

```ts
export type V1BountyPrizes = {
    success: true;
    enabled: false;
} | {
    success: true;
    enabled: true;
    show_occurrence: boolean;
    show_winners: boolean;
    show_inventory_preview: boolean;
    sections: V1BountySection[];
    pool_sections: V1BountyPoolSection[];
};
```

### `V1BountySection`

```ts
export type V1BountySection = {
    kind: "milestone_group";
    id: string;
    name: string;
    counter_starts_at?: string | null;
    bounties: V1BountyItem[];
} | {
    kind: "individual";
    id?: string;
    name: string;
    bounties: V1BountyItem[];
} | {
    kind: "inventory_preview";
    id?: string;
    name: string;
    items: V1BountyInventoryItem[];
};
```

### `V1BountySummary`

`bounty()`. `total_pool` and `pool_raw` are in each token's smallest unit.

```ts
export interface V1BountySummary {
    success: true;
    remaining_bounties: number;
    free_mint_bounties: number;
    total_pool: number;
    /** One symbol, `"tokens"` when the pool spans several, or null when there is none. */
    token_symbol: string | null;
    tokens: Array<{
        address: string;
        symbol: string | null;
        decimals: number;
        pool_raw: number;
    }>;
    has_bounties: boolean;
}
```

### `V1Capabilities`

Describes the features a collection requires and whether the core mint flow supports them. When `supportedBySurface` is false, offer the hosted `mintUrl` when available.

```ts
export interface V1Capabilities {
    requiresFeatures: string[];
    supportedBySurface: boolean;
    mintUrl: string | null;
}
```

### `V1ClaimCodeBenefits`

`claimCodeBenefits()`. All zeros with `source: null` when the wallet has redeemed
nothing. `success` is false (and everything zero) when the server could not look it up,
so do not read zeros as "no benefits" without checking it.

```ts
export interface V1ClaimCodeBenefits {
    success: boolean;
    freeMints: number;
    discountPercent: number;
    discountFixed: number;
    discountRemaining?: number;
    packTierId?: string | null;
    source: null | {
        type: "free_mint";
        batchName: string | null;
        allocation: number | null;
        used: number;
        batchId?: string;
        packTierId?: string | null;
    } | {
        type: "discount";
        batchName: string | null;
        percent?: number;
        fixed?: number;
        allocation: number;
        used: number;
        remaining: number;
        batchId?: string;
    };
}
```

### `V1ClaimCodeCheck`

`validateClaimCode()` — the v1 answer. A code for another drop answers `{ valid: false }`.

```ts
export interface V1ClaimCodeCheck {
    valid: boolean;
    grantType?: "whitelist" | "free_mint" | "discount" | "external" | "nft_redemption";
    mintAllocation?: number | null;
    discountPercentage?: number | null;
    discountFixed?: number | null;
    usesRemaining?: number | null;
    [k: string]: unknown;
}
```

### `V1ClaimCodes`

`claimCodes()`.

```ts
export interface V1ClaimCodes {
    hasClaimCodes: boolean;
    hasDiscountCodes: boolean;
    hasWhitelistCodes: boolean;
    hasPackCodes: boolean;
}
```

### `V1Collection`

```ts
export interface V1Collection {
    collection: {
        id: string;
        shortId: string | null;
        name: string | null;
        symbol: string | null;
        description: string | null;
        image: string | null;
        bannerImage: string | null;
        chain: string | null;
        collectionAddress: string | null;
        contractAddress: string | null;
        externalUrl: string | null;
        twitter: string | null;
        discord: string | null;
        isVerified: boolean;
    };
    stats: {
        totalSupply: number;
        mintedCount: number;
        availableCount: number;
        percentMinted: number;
    };
    /** `all` INCLUDES ended phases, for displaying the full schedule. */
    phases: {
        all: V1Phase[];
        active: V1Phase[];
        upcoming: V1Phase[];
    };
    capabilities: V1Capabilities;
    /** GraveMint's clock. Render countdowns against this, never `Date.now()`. */
    serverTime: string;
}
```

### `V1DutchPrice`

`dutchPrice()`. `price` is the live figure; the rest explains how it got there.

```ts
export interface V1DutchPrice {
    success: true;
    price: number;
    basePrice: number;
    surgePremium: number;
    decayAmount: number;
    isSurging: boolean;
    mintsInWindow: number;
    totalMints: number;
    surgeThreshold: number;
    floorPrice: number;
    ceilingPrice: number;
    surgeWindowMinutes: number;
    startedAt: string | null;
    lastMintAt: string | null;
    /** The phase's Dutch-auction settings, as configured. */
    config: Record<string, unknown>;
    /** Milliseconds since the epoch. */
    timestamp: number;
}
```

### `V1Eligibility`

```ts
export interface V1Eligibility {
    gated: boolean;
    meetsRequirements?: boolean;
    onAllowlist?: boolean | null;
    spotsAllocated?: number | null;
    spotsRemaining?: number | null;
    requirements?: Array<{
        type: string;
        met: boolean;
        description: string;
    }>;
    /**
     * `name` can be null at runtime for an unnamed phase; it stays typed `string` because
     * narrowing a published type is a breaking change here. `startDate`/`endDate` are ISO
     * strings or null (open-ended).
     */
    phase: {
        id: string;
        name: string;
        hasStarted: boolean;
        hasEnded: boolean;
        startDate?: string | null;
        endDate?: string | null;
    };
    message?: string;
}
```

### `V1ExecuteBatchResult`

`executeBatch()`. ALWAYS answered with HTTP 200, even when every transaction failed,
and `success` is true when ANY landed — read `results[]` and the counts, never
`success` alone.

```ts
export interface V1ExecuteBatchResult {
    success: boolean;
    results: V1BatchTransactionResult[];
    totalMinted: number;
    successfulTransactions: number;
    failedTransactions: number;
    executionTimeMs: number;
    /** Kept from the 1.2.x `Record<string, unknown>` type, so existing reads still compile. */
    [k: string]: unknown;
}
```

### `V1ExecuteResult`

`execute()` — the server's answer for ONE signed transaction.

A failure is thrown, never returned. Fields other than the reveal settings and
`totalCost` / `currency` can be absent: a session the server recovered after an
interruption answers with the count only (`minted`) and no `signature` or `nfts`.

```ts
export interface V1ExecuteResult {
    success: true;
    /** How many NFTs this transaction minted (a COUNT — the NFTs themselves are in `nfts`). */
    minted: number;
    signature?: string;
    /** Same value as `signature`. */
    transactionHash?: string;
    chainType: string;
    nfts?: V1MintedNft[];
    /** What the collector paid, in `currency`: mint price plus platform fee. */
    totalCost: number;
    currency: string;
    collectionStats?: {
        totalSupply: number;
        mintedCount: number;
        percentMinted: number;
        isMintedOut: boolean;
    } | null;
    collectionUpdate?: {
        itemsRedeemed: number;
        isFrozen: boolean;
        autoUnfrozen: boolean;
    } | null;
    delayedReveal?: boolean;
    instantRevealAfterMint?: boolean;
    timeDelayedReveal?: boolean;
    revealDelayMinutes?: number | null;
    revealAfter?: string | null;
    revealAnimationUrl: string | null;
    revealTransitionType: string;
    revealAnimationTrigger: string;
    revealTapCaption: string | null;
    isPlatformPaid?: boolean;
    bountyInfo?: {
        directBounties: Array<Record<string, unknown>>;
    } | null;
    /** Never set on a single result — lets `if (res.results)` tell a batch apart. */
    results?: undefined;
    /**
     * 1.2.x typed this result as `Record<string, unknown>`; the index signature keeps code that
     * read other fields that way compiling within 1.x ( review).
     */
    [k: string]: unknown;
}
```

### `V1Gallery`

`gallery()`.

```ts
export interface V1Gallery {
    success: true;
    nfts: V1GalleryNft[];
    total: number;
    limit: number;
    offset: number;
}
```

### `V1GalleryNft`

One NFT that can still be minted.

```ts
export interface V1GalleryNft {
    id: string;
    /** null for a limited-edition drop, whose editions share one artwork. */
    token_id: number | null;
    name: string | null;
    description: string | null;
    image_url: string | null;
    preview_image_url: string | null;
    cover_art_url: string | null;
    animation_url: string | null;
    /** Always null here: full audio is never public. Use `audio_preview_url`. */
    audio_url: null;
    audio_preview_url: string | null;
    media_type: string | null;
    preview_url: string | null;
    preview_start_time: number | null;
    preview_duration: number | null;
    audio_duration_seconds: number | null;
    mint_status: string | null;
    /** The NFT's metadata attributes, passed through as stored. */
    attributes: unknown;
    is_master_edition: boolean;
    current_edition_supply: number;
    max_edition_supply: number | null;
    edition_number: number | null;
    master_nft_id: string | null;
    /** Set when the NFT is reserved for one wallet. */
    reservation_wallet: string | null;
    reserved_by: string | null;
}
```

### `V1LeaderboardEntry`

One entry on a leaderboard. `platformRank` is the wallet's GraveLink rank name.

```ts
export interface V1LeaderboardEntry {
    rank: number;
    walletAddress: string;
    displayName: string | null;
    avatarUrl: string | null;
    platformRank: string;
    effects: V1ProfileEffect[];
}
```

### `V1MintBatchOutcome`

What `mint()` returns for a quantity above 1: the batch answer, annotated. When any
transaction failed, `success` is false, `partial` says whether SOME landed, `minted`
of `requested` is the tally, and `message` is a sentence safe to show the collector.

```ts
export interface V1MintBatchOutcome extends V1ExecuteBatchResult {
    partial?: boolean;
    requested?: number;
    minted?: number;
    message?: string;
}
```

### `V1MintedItem`

One NFT in a minted feed. Regular drops and limited editions carry different extras,
so every field outside the common set is optional.

```ts
export interface V1MintedItem {
    id: string;
    /** null for a limited-edition drop — use `editionNumber` there. */
    tokenId: number | null;
    name: string | null;
    image: string | null;
    fullImageUrl: string | null;
    mintAddress: string | null;
    mintedAt: string | null;
    isRevealed: boolean;
    ownerWallet: string | null;
    attributes: unknown[];
    minterDisplayName: string | null;
    minterAvatarUrl: string | null;
    minterEffects: V1ProfileEffect[];
    reactions?: Record<string, number>;
    editionNumber?: number | null;
    packTierName?: string | null;
    rarityRank?: number | null;
    rarityTier?: string | null;
    rarityScore?: number | null;
    bounty?: V1NftBounty | null;
    isCrossChain?: boolean;
    sourceChain?: string | null;
}
```

### `V1MintedNft`

One NFT a successful execute minted.

```ts
export interface V1MintedNft {
    nftId?: string;
    /** null for a limited-edition drop — use `editionNumber` there. */
    tokenId: number | string | null;
    name: string | null;
    mintAddress?: string;
    imageUrl: string | null;
    animationUrl?: string | null;
    mediaType: string;
    previewImageUrl: string | null;
    isRevealed: boolean;
    revealAfter: string | null;
    editionNumber?: number;
    maxEditionSupply?: number;
    rarity_score?: number | null;
    rarity_rank?: number | null;
    rarity_tier?: string | null;
    pityTriggered?: boolean;
    poolName?: string;
    /** `amount` is in the token's smallest unit. */
    bounty?: {
        bountyType: string;
        amount: number | null;
        tokenSymbol: string | null;
        payoutStatus: string;
    } | null;
}
```

### `V1NftBounty`

A bounty attached to a minted NFT. `amount` is in the token's smallest unit.

```ts
export interface V1NftBounty {
    bountyType: string;
    amount: number | null;
    tokenSymbol: string | null;
    payoutStatus: string;
    memo?: string | null;
}
```

### `V1PeggedPrice`

`peggedPrice()`. The quote expires at `expiresAt`; refresh it rather than reuse it.

```ts
export type V1PeggedPrice = (V1PeggedPriceBase & {
    pegMode: "usd";
    usdEquivalent: number;
}) | (V1PeggedPriceBase & {
    pegMode: "native";
    nativeEquivalent: number | null;
    nativePrice: number;
});
```

### `V1PeggedPriceBase`

Fields shared by both peg modes of `peggedPrice()`. Times are milliseconds since the epoch.

```ts
export interface V1PeggedPriceBase {
    success: true;
    phaseId: string;
    tokenAmount: number;
    tokenSymbol: string | null;
    tokenDecimals: number | null;
    tokenPrice: number;
    usdValue: number;
    slippageTolerance: number;
    source: string;
    isStale: boolean;
    quotedAt: number;
    expiresAt: number;
    validitySeconds: number;
}
```

### `V1Phase`

```ts
export interface V1Phase {
    id: string;
    name: string | null;
    status: "active" | "upcoming" | "ended";
    startDate: string | null;
    endDate: string | null;
    /** Resolved. See the file header — never recompute this. */
    priceDisplay: PriceDisplay;
    bogo: {
        buy: number;
        get: number;
    } | null;
    isGated: boolean;
    maxPerWallet: number | null;
    maxPerTransaction: number | null;
    phaseSupply: number | null;
    /** Derived from the SERVER clock, so a skewed device clock cannot mislead. */
    msUntilStart: number | null;
    msUntilEnd: number | null;
}
```

### `V1ProfileEffect`

A minter's cosmetic profile effect, as rendered next to their name.

```ts
export interface V1ProfileEffect {
    effect_type: string | null;
    effect_category: string | null;
    config: unknown;
}
```

### `V1RecentlyMinted`

`recentlyMinted()`. `total` is the length of this feed, not the drop's supply.

```ts
export interface V1RecentlyMinted {
    success: true;
    nfts: V1RecentMint[];
    total: number;
    delayedRevealEnabled: boolean;
    editionType: string;
    allowImageDownload: boolean;
}
```

### `V1RecentMint`

One entry in the live "just minted" feed.

```ts
export interface V1RecentMint extends V1MintedItem {
    masterNftId?: string | null;
    previewImage: string | null;
    maxEditionSupply: number | null;
    isMasterEdition: boolean;
    currentEditionSupply: number | null;
    animationUrl: string | null;
    mediaType: string | null;
    isPatron: boolean;
    customTag: string | null;
    generationStatus?: string | null;
    currentPlaceholderSequence?: number | null;
    audioUrl?: string | null;
    audioPreviewUrl?: string | null;
    coverArtUrl?: string | null;
}
```

### `V1TokenPrices`

`tokenPrices()`. A price of 0 means unavailable — check `sources[symbol]`.

```ts
export interface V1TokenPrices {
    success: true;
    prices: Record<string, number>;
    sources: Record<string, string>;
    /** Milliseconds since the epoch. */
    timestamp: number;
    cacheTTL: number;
}
```

### `V1TopHolders`

`topHolders()`. Up to 10. `error` is set (with an empty list) when on-chain holder data
could not be read — the request itself still succeeds, so check it before rendering
"no holders".

```ts
export interface V1TopHolders {
    success: true;
    topHolders: Array<V1LeaderboardEntry & {
        holdCount: number;
    }>;
    /** Distinct holders found, not the drop's supply. */
    total: number;
    error?: string;
}
```

### `V1TopMinters`

`topMinters()`. Up to 10.

```ts
export interface V1TopMinters {
    success: true;
    topMinters: Array<V1LeaderboardEntry & {
        mintCount: number;
    }>;
    total: number;
}
```

### `V1Trait`

```ts
export interface V1Trait {
    traitType: string;
    uniqueValues: number;
    values: V1TraitValue[];
}
```

### `V1Traits`

`traits()`. Before a delayed reveal, `traits` is empty and `message` says why;
`totalNfts` and `methodology` are only present once traits are public.

```ts
export interface V1Traits {
    success: true;
    traits: V1Trait[];
    totalNfts?: number;
    methodology?: string;
    message?: string;
}
```

### `V1TraitValue`

```ts
export interface V1TraitValue {
    value: string;
    count: number;
    minted: number;
    available: number;
    probability: number;
    /** 0-100. */
    percentage: number;
    informationContent: number;
    rarityScore: number;
}
```

### `V1WalletMints`

`walletMints()`. `phaseMints` is keyed by phase id. `totalMinted` counts every NFT this
wallet minted from the drop, bonus mints included — it is not a sum of `phaseMints`.

```ts
export interface V1WalletMints {
    success: true;
    walletAddress: string;
    collectionId: string;
    phaseMints: Record<string, V1WalletPhaseMints>;
    totalMinted: number;
}
```

### `V1WalletPhaseMints`

One phase in `walletMints()`.

```ts
export interface V1WalletPhaseMints {
    phaseName: string | null;
    minted: number;
    /** 0 means unlimited. */
    maxPerWallet: number;
    whitelistAllocation: number | null;
    nftGateAllocation: number | null;
    tokenGateAllocation: number | null;
    allocationDetails: Array<{
        type: "whitelist";
        allocation: number;
    } | {
        type: "nft_gate";
        ruleName: string;
        multiplier: number;
        collections: unknown;
    } | {
        type: "token_gate";
        ruleName: string;
        multiplier: number;
        tokenAddress: unknown;
    }>;
    hasAllocationOverride: boolean | null;
    /** null when the phase has no per-wallet limit. */
    remaining: number | null;
    canMintMore: boolean;
    isPackPhase?: boolean;
}
```

---
Source: https://docs.deads.io/sdk/gravemint-reference
Markdown: https://docs.deads.io/sdk/gravemint-reference.md
