Catalog
Browsing the inventory that is for sale, and where each wallet's price comes from.
The catalog is the set of wallets currently listed for sale. Wallets leave it the moment a quote reserves them and never come back, so treat a page of results as a snapshot rather than a stable list.
What a wallet looks like
Each entry carries the history that makes it worth buying:
balance, what the wallet holds right now, in base units.funded_at,first_tx_at,last_tx_at, its timeline. Age is derived fromfunded_at.tx_count, how many transactions it has made.funding_sourceandfunding_exchange, where the money originally came from. The first names the provider, the second the actual exchange when the wallet was funded from one.tier,persona_name,timezone_name, the quality band and the behavioural profile the wallet was aged under.token_holdings, non-native tokens sitting in the wallet, if any.
Two prices, and they are not the same
cost_basis is what the wallet costs the platform. user_price is what you
will be charged, and it is the one that matters: platform margin for the
wallet's tier, plus your own organisation's resale markup, on top of the base.
On a catalog response user_price is computed live, with exactly the pricing a
quote would apply, so the number you display is the number the order charges.
On a sold wallet the same field means something slightly different: the price
actually paid, frozen at settlement.
Both are in base units. Convert to USD with GET /prices if you are showing
them to a human.
Filtering
GET /catalog takes the filters you would expect, covering chain, balance
range, price range, age range and transaction count, plus a few that are
specific to this inventory:
sources,tier,personaandtimezoneare comma-separated multi-selects:tier=tier1,tier2.min_funding_gap_secondsthins the results so that no two returned wallets were funded within that many seconds of each other. A batch of wallets all funded in the same minute is a pattern, and this is how you avoid buying one.gap_withtakes a comma-separated list of Unix timestamps and keeps only wallets whosefunded_atis at leastmin_funding_gap_secondsaway from every one of them. Useful when you already hold wallets and want the next lot not to line up with them. It requiresmin_funding_gap_secondsto be set.
sort defaults to random, which is not really random. It interleaves funding
sources and funding windows round-robin, so a page, and any lot you pick out of
it, spreads across funders and time instead of clustering. order is ignored in
that mode. If you want plain chronological order, ask for sort=age explicitly.
Authorization
bearerAuth JWT from /auth/login (users) or an org API key (mk_...) for integrations.
In: header
Query Parameters
Max rows for this page (per-request cap; page past it via cursor).
int6450Opaque keyset cursor from a prior response's next_cursor. When set, returns the page strictly after it.
nullComma-separated reference timestamps (Unix epoch seconds). A wallet is kept only if its funded_at is at least min_funding_gap_seconds away from each of them, so its funding gap never collides with these times. Composes with the mutual spacing above.
int64int32int64Balance bounds, in base units (lamports on Solana, wei on EVM) — the same scale as WalletDto.balance. Convert native → base client-side.
Minimum funding gap, in seconds. When set (>0) it enforces mutual spacing: the returned wallets are thinned along funded_at so no two are funded within this many seconds of each other (like a quote's min_gap_seconds). The same threshold also applies to gap_with when that is provided. Required when gap_with is set.
int64Price bounds on our price (cost_basis), also in base units (same scale as balance). For USD filtering convert client-side via /prices.
Transaction-count bounds (inclusive) on tx_count.
int32asc (default) | desc.
Comma-separated persona names (multi-select), e.g. memecoin_degen,hodler.
random (default) | age | balance | price | tx_count. random interleaves funding source and funding time round-robin, so a page (or a lot picked from it) spreads across funders and funding windows instead of clustering on one; order is ignored in that mode. age is the un-diversified chronological order for callers that want it explicitly.
Comma-separated funding sources (multi-select), e.g. binance,kraken.
Comma-separated quality tiers (multi-select), e.g. tier1,tier2.
Comma-separated timezone-profile names (multi-select).
Response Body
application/json
curl -X GET "https://example.com/catalog"{ "items": [ { "aging_status": "string", "balance": "string", "buyer_ref": "string", "chain": "string", "cost_basis": "string", "created_at": "string", "first_tx_at": "string", "funded_at": "string", "funding_exchange": "string", "funding_source": "string", "id": "string", "imported": true, "last_tx_at": "string", "network": "string", "owner_org_id": "string", "persona_name": "string", "pubkey": "string", "sale_id": "string", "sold_at": "string", "source_kind": "string", "status": "string", "target_age_days": 0, "tier": "string", "timezone_name": "string", "token_holdings": [ { "balance": "string", "decimals": 0, "mint": "string", "symbol": "string", "ui_multiplier": "string", "usd_value": 0 } ], "tx_count": 0, "user_price": "string" } ], "next_cursor": "string"}Counting and faceting before you fetch
GET /catalog/count answers the same filters with a single number. It is cheap
enough to call on every keystroke of a filter form.
GET /catalog/facets returns the bounds and histograms of the current
selection: maximum balance, price, transaction count and age, four histograms to
draw sliders against, and the distinct tiers, personas and timezones
available. It is what you build a filter panel out of.
GET /catalog/sources lists the distinct funding sources present, optionally
narrowed to one chain.
Authorization
bearerAuth JWT from /auth/login (users) or an org API key (mk_...) for integrations.
In: header
Query Parameters
Max rows for this page (per-request cap; page past it via cursor).
int6450Opaque keyset cursor from a prior response's next_cursor. When set, returns the page strictly after it.
nullComma-separated reference timestamps (Unix epoch seconds). A wallet is kept only if its funded_at is at least min_funding_gap_seconds away from each of them, so its funding gap never collides with these times. Composes with the mutual spacing above.
int64int32int64Balance bounds, in base units (lamports on Solana, wei on EVM) — the same scale as WalletDto.balance. Convert native → base client-side.
Minimum funding gap, in seconds. When set (>0) it enforces mutual spacing: the returned wallets are thinned along funded_at so no two are funded within this many seconds of each other (like a quote's min_gap_seconds). The same threshold also applies to gap_with when that is provided. Required when gap_with is set.
int64Price bounds on our price (cost_basis), also in base units (same scale as balance). For USD filtering convert client-side via /prices.
Transaction-count bounds (inclusive) on tx_count.
int32asc (default) | desc.
Comma-separated persona names (multi-select), e.g. memecoin_degen,hodler.
random (default) | age | balance | price | tx_count. random interleaves funding source and funding time round-robin, so a page (or a lot picked from it) spreads across funders and funding windows instead of clustering on one; order is ignored in that mode. age is the un-diversified chronological order for callers that want it explicitly.
Comma-separated funding sources (multi-select), e.g. binance,kraken.
Comma-separated quality tiers (multi-select), e.g. tier1,tier2.
Comma-separated timezone-profile names (multi-select).
Response Body
application/json
curl -X GET "https://example.com/catalog/count"{ "count": 0}Authorization
bearerAuth JWT from /auth/login (users) or an org API key (mk_...) for integrations.
In: header
Query Parameters
Max rows for this page (per-request cap; page past it via cursor).
int6450Opaque keyset cursor from a prior response's next_cursor. When set, returns the page strictly after it.
nullComma-separated reference timestamps (Unix epoch seconds). A wallet is kept only if its funded_at is at least min_funding_gap_seconds away from each of them, so its funding gap never collides with these times. Composes with the mutual spacing above.
int64int32int64Balance bounds, in base units (lamports on Solana, wei on EVM) — the same scale as WalletDto.balance. Convert native → base client-side.
Minimum funding gap, in seconds. When set (>0) it enforces mutual spacing: the returned wallets are thinned along funded_at so no two are funded within this many seconds of each other (like a quote's min_gap_seconds). The same threshold also applies to gap_with when that is provided. Required when gap_with is set.
int64Price bounds on our price (cost_basis), also in base units (same scale as balance). For USD filtering convert client-side via /prices.
Transaction-count bounds (inclusive) on tx_count.
int32asc (default) | desc.
Comma-separated persona names (multi-select), e.g. memecoin_degen,hodler.
random (default) | age | balance | price | tx_count. random interleaves funding source and funding time round-robin, so a page (or a lot picked from it) spreads across funders and funding windows instead of clustering on one; order is ignored in that mode. age is the un-diversified chronological order for callers that want it explicitly.
Comma-separated funding sources (multi-select), e.g. binance,kraken.
Comma-separated quality tiers (multi-select), e.g. tier1,tier2.
Comma-separated timezone-profile names (multi-select).
Response Body
application/json
curl -X GET "https://example.com/catalog/facets"{ "age_hist": [ 0 ], "balance_hist": [ 0 ], "count": 0, "max_age_days": 0.1, "max_balance": "string", "max_price": "string", "max_tx": 0, "personas": [ "string" ], "price_hist": [ 0 ], "tiers": [ "string" ], "timezones": [ "string" ], "tx_hist": [ 0 ]}Authorization
bearerAuth JWT from /auth/login (users) or an org API key (mk_...) for integrations.
In: header
Query Parameters
Response Body
application/json
curl -X GET "https://example.com/catalog/sources"{ "sources": [ "string" ]}From a page to an order
There are two ways to turn a selection into a quote.
Let the server pick. Pass the same filters to POST /quote with a count,
and it selects that many matching wallets at reserve time. Nothing you saw needs
to still be there.
Pick them yourself. Send the wallet_ids you showed the buyer, and the lot
is exactly what they chose. If any single one has been reserved by someone else
in the meantime, though, the whole call fails with 409 and reserves nothing.
The second is the right choice when a human has been looking at a list. The first is the right choice for anything automated.
Last updated on