# The read model

`gm.v1.collection(identifier)` returns the collection, supply, phase schedule and supported features in one response. Use it to build the initial mint page, then request wallet-specific eligibility and mint counts when a collector connects.

```ts
const drop = await gm.v1.collection('your-drop');
// drop.collection   — name, images, chain and socials
// drop.stats        — mintedCount, totalSupply and availableCount
// drop.phases       — { active, upcoming, all }, each an array
// drop.capabilities — supported features and the hosted mint URL
// drop.serverTime   — server timestamp for countdowns
```

## Phases

Each phase includes its status, schedule, supply, wallet limits and `priceDisplay`. `phases.active` and `phases.upcoming` are arrays; `phases.all` also includes ended phases.

Use the returned phase `status` to decide what to display. GraveMint manages phase transitions on the server. Refresh the collection response to keep the schedule current, and use `serverTime` with `msUntilStart` or `msUntilEnd` for countdowns. A countdown reaching zero is a reason to refresh, rather than to change the phase status locally.

## Price display {#pricing-—-a-union-never-a-number}

`priceDisplay` describes what can be shown before a wallet prepares a mint. Handle each `kind` explicitly:

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

| Kind | Meaning | Display |
| --- | --- | --- |
| `amount` | A resolved amount | Amount and currency; use `isFree` for the “Free” label |
| `range` | A price within a range | “0.45–1.2 SOL” |
| `hidden` | Price is withheld until the wallet qualifies | “Price revealed when you qualify” |
| `unknown` | No display price is available for this request | “See on GraveMint” or “—” |

```ts
function renderPrice(p: PriceDisplay) {
  switch (p.kind) {
    case 'amount': return p.isFree ? 'Free' : `${p.amount} ${p.currency}`;
    case 'range': return `${p.min}–${p.max} ${p.currency}`;
    case 'hidden': return 'Price revealed when you qualify';
    case 'unknown': return 'See on GraveMint';
  }
}
```

Keep `hidden` and `unknown` distinct from zero. A pegged display price can be marked `approximate`. Use [`peggedPrice(phaseId)`](https://docs.deads.io/api/gravemint-v1.md#pricing) to refresh the token amount without reloading the collection. v1 phases do not expose a raw `price` field.

The final price breakdown comes from `prepare`. It includes the applicable wallet benefits, fees and mint settings. Display the returned values instead of rebuilding that calculation from phase fields. Only call `prepare` when the collector is ready to mint, because it reserves supply.

## Eligibility

```ts
const verdict = await gm.v1.eligibility(collectionId, phaseId, wallet);
```

GraveMint checks the phase requirements, including allowlists and NFT holdings, on the server. The response reports eligibility separately from the phase's time window, so an upcoming phase can show that a wallet qualifies before minting starts.

```ts
const qualifies = !verdict.gated || verdict.meetsRequirements === true;
const canMintNow = qualifies && verdict.phase.hasStarted && !verdict.phase.hasEnded;
```

`prepare` checks the current requirements again when minting begins.

## Per-wallet limits

```ts
const mints = await gm.v1.walletMints(collectionId, wallet);
```

Use `walletMints` for the wallet's minted and remaining counts. It includes bonus mints, such as BOGO and bounty mints. Eligibility evaluates allocations using different counting rules, so its fields are not a substitute for the wallet-mint response.

## Supported features {#capabilities-—-degrading-honestly}

Check `capabilities.supportedBySurface` before enabling the mint panel. `requiresFeatures` describes the features the collection needs. Collections that use a feature outside the core mint flow, such as a pack or generative builder, can be opened on the hosted mint page.

```tsx
if (!drop.capabilities.supportedBySurface) {
  return drop.capabilities.mintUrl
    ? <a href={drop.capabilities.mintUrl}>Mint on GraveMint</a>
    : <p>This collection is not available through this integration.</p>;
}
```

## Keeping the page current {#what-this-buys-you}

Refresh collection and wallet data after a mint and when a phase countdown expires. Keep the last successful response visible during refreshes, with a loading or error state where appropriate. The [React recipe](https://docs.deads.io/recipes/react.md) shows how to connect the read model to a signer.

---
Source: https://docs.deads.io/concepts/read-model
Markdown: https://docs.deads.io/concepts/read-model.md
