Gary Club
Wallet Snapshot

Every wallet we can associate with a Giraffe

A live, public, no-auth feed for anyone running an airdrop, an allowlist, or a holder check against Gary Club. Wallets are grouped per holder, so you can treat a cluster as one person instead of guessing at it.

No key, no signup
Both formats are open. GET them from a browser, a script, an n8n flow, or an agent. CORS is *.

Who is in the feed#

A wallet appears for either of two independent reasons, and the type field tells you which:

memberhas a Gary Club account
A Gary Club member. Their entry is keyed by their Gary Club custodial wallet and lists every address they have connected — so members appear whether or not they have a Giraffe.
non_memberholds a Giraffe, no account
A wallet holding a Giraffe Tower on-chain that has never been connected to a Gary Club account. We have no verified way to link a stranger’s wallets together, so these entries are always a single address — we will not guess at a cluster.
platformGary Club itself
A Gary Club platform wallet (inventory or treasury). Labelled so you don’t airdrop to us by accident.

What it tells you — and what it doesn’t#

This feed is deliberately narrow. It answers “which addresses belong to the same holder, and is that holder a member?” and nothing more.

Discloses
Wallet addresses · which addresses belong to the same holder (members only) · membership status · whether a Giraffe is associated with the holder, as a boolean.
Withholds, by design
How many Giraffes anyone has · whether a Giraffe is owned, rented, delegated, or assigned — all four read as giraffe: true · roles, badges, traits, rarity, or token balances · names, emails, phone numbers, avatars, bios, socials, and internal ids.

The collapse of owned / rented / delegated into a single boolean is the point of the design, not a gap in it. If you need to distinguish them, this feed is not the right source and we will not add a field that splits them.

Complete — there is no opt-out
If a wallet holds a Giraffe Tower, it is in this feed. Members cannot hide from it and there is no exclusion list, so an address missing from the feed genuinely has no Giraffe rather than having opted out. That completeness is what makes a holder check trustworthy: silent holes would be indistinguishable from denials. The protection is the narrow disclosure above, not omission.

Two things that would otherwise be holes, and are not: listed Giraffes still count — a Giraffe listed for sale sits in a marketplace escrow program, and we resolve it back to the seller, so putting yours on the market does not drop you from the feed. And a Giraffe that has been delegated or rented counts for both sides: the owner never stopped owning it, and the member using it reads as having one too.

A Giraffe is the Giraffe Tower
Not a narrowing for this feed — it is what a Giraffe is at Gary Club. The Giraffe Tower is the main collection and the membership NFT, and it is what Giraffe-holder access means everywhere on the platform.

Our other collections — MAGA Giraffe, Dark MAGA Giraffe, Vibin Giraffe, Giraffe Glimpses, Giraffish Moments, Gary Club Stacker, Golden Ticket — are separate collections, not Giraffes, and holding one does not put a wallet in this feed.

Endpoints#

The snapshot, grouped per holder

GEThttps://gary.club/snapshot.json
One entry per holder, sorted by wallet so consecutive snapshots diff cleanly. This is the canonical format.
Request
curl https://gary.club/snapshot.json

Response:

JSON
{
  "schema": "gary-club-wallet-snapshot/2",
  "generated_at": "2026-08-09T19:20:11.482Z",
  "key": "wallet — for a member, their Gary Club custodial SOL wallet; ...",
  "disclosure": {
    "discloses": ["wallet addresses", "membership status", "..."],
    "withholds": ["how many Giraffes anyone has", "..."]
  },
  "collection": {
    "giraffe_tower": "H5P4frZiXzTKucCPHyFwQoSSY5bVPG5BPdeeKAnX7CnA",
    "supply": 7291
  },
  "freshness": {
    "membership": "live — read from the database on each build",
    "giraffe_index_updated_at": "2026-08-09T19:11:44.776Z"
  },
  "counts": {
    "entries": 931,
    "wallets": 1218,
    "members": 489,
    "non_members": 441,
    "platform": 1,
    "with_giraffe": 581,
    "without_giraffe": 350,
    "giraffes_in_marketplace_escrow": 90,
    "excluded_without_wallet": 5
  },
  "entries": [
    {
      "wallet": "Ga1ExampLeCustodia1Wa11etAddress1111111111",
      "wallets": [
        "Ga1ExampLeCustodia1Wa11etAddress1111111111",
        "Ga1ExampLeConnectedWa11etAddress2222222222"
      ],
      "type": "member",
      "giraffe": true,
      "member_since": "2026-03-17"
    },
    {
      "wallet": "Ga1ExampLeNonMemberWa11etAddress3333333333",
      "wallets": ["Ga1ExampLeNonMemberWa11etAddress3333333333"],
      "type": "non_member",
      "giraffe": true
    }
  ]
}

Entry fields#

walletstring · the unique key
For a member, their Gary Club custodial SOL wallet. For anyone else, the address itself. Unique across the whole feed.
walletsstring[]
Every address attributable to this same holder, key first. Match against this, not wallet — a member may hold assets in any of them. No address appears in more than one entry.
type'member' | 'non_member' | 'platform'
Membership status. See the table above.
giraffeboolean
Whether a Giraffe is associated with this holder. Carries no quantity, and does not distinguish how they got it.
member_sincestring · YYYY-MM-DD · members only
The date the member joined Gary Club. Absent on non-member and platform entries.

The same snapshot, one row per wallet

GEThttps://gary.club/snapshot.csv
Flattened for spreadsheet and airdrop tooling. Rows sharing a cluster value are the same holder; kind is custodial, connected, or holder. The holder-level fields repeat on every row, so a naive dedupe by cluster loses nothing.
Request
curl -o gary-club-wallets.csv https://gary.club/snapshot.csv
csv
wallet,cluster,kind,type,giraffe,member_since
Ga1ExampLeCustodia1Wa11etAddress1111111111,Ga1ExampLeCustodia1Wa11etAddress1111111111,custodial,member,true,2026-03-17
Ga1ExampLeConnectedWa11etAddress2222222222,Ga1ExampLeCustodia1Wa11etAddress1111111111,connected,member,true,2026-03-17
Ga1ExampLeNonMemberWa11etAddress3333333333,Ga1ExampLeNonMemberWa11etAddress3333333333,holder,non_member,true,

Freshness#

The feed is rebuilt from the database on request behind a 30-second cache, so generated_at moves continuously. Membership, wallet connections, rentals, and delegations are live at write time.

On-chain Giraffe holding is the one input that is not read per request: it comes from a full-collection index refreshed hourly, and the feed publishes its exact timestamp as freshness.giraffe_index_updated_at rather than asking you to take freshness on trust. A wallet that bought a Giraffe minutes ago may not appear until the next index run.

Check X-Snapshot-Stale
If the feed cannot rebuild, it serves the last good copy rather than an empty list — an empty snapshot presented as the answer is worse than a slightly old one. When that happens the response carries X-Snapshot-Stale: true and X-Snapshot-Age-Seconds. Treat true as “retry later”, never as “this holder no longer qualifies”.

Rate limits and caching#

60 requests per minute per source IP, on each format. Responses are Cache-Control: public, max-age=30 — please cache your side rather than polling in a loop. The whole snapshot is a single request; there is no pagination and no partial fetch.

Reconciling against the collection#

Every Giraffe Tower in the collection is accounted for. collection.supply equals the Giraffes held by members, plus those held by non-members, plus platform-held, plus counts.giraffes_in_marketplace_escrow.

That last bucket is why the numbers add up: a Giraffe listed for sale sits in a marketplace escrow program address, not a wallet anyone holds. Those are counted but never published as entries, because listing a program address as a holder invites an airdrop straight into it.

Members without a wallet
counts.excluded_without_wallet reports members who have signed up but have no custodial wallet yet. They have no key to publish, so they are counted rather than listed.