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.
What it does not carry is the address. pubkey is present on every entry and
always empty: the address of a wallet nobody has bought never leaves the
platform, and it reaches you with the keys once the order settles.
The listing also leaves out everything that only means something once a wallet
has an owner. status, owner_org_id, buyer_ref, sold_at and sale_id are
on GET /wallets, where they describe your own inventory, and not here.
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. For where each of those numbers comes from (the funding cost
underneath, the tier margin, and your own), see
Price breakdown.
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.
How a page is dealt
A page is spread before it is returned, whichever sort you asked for. It alternates between funding sources, tiers, personas, timezone profiles and funding windows, and your sort applies within each of those groups.
So a page reads as your sort dealt across the inventory rather than as a plain
ordering. Ask for two funding sources sorted by price and you get both, cheapest
first within each, instead of the cheaper one's entire stock. sort still
defaults to random, where the spread is the whole order and order is
ignored.
A spread page is addressed by position rather than by the value of its sort
column. Follow next_cursor and you will not notice.
diversify=false turns all of it off and gives you a plain sorted page, for
a caller that needs the sort column strictly monotonic from one page to the
next. It is accepted on /catalog, /catalog/count and /catalog/facets
alike.
Which inventory you are looking at
By default the catalog is the marketplace: wallets the platform produced and
sells. An organisation with the private marketplace
switched on also has a stock of its own, the wallets its own funding plans
produced, and scope=private reads that one instead.
The two never mix. A private wallet is listed for its organisation only, is
never priced (user_price comes back as "0", it is your stock), and a quote
on it is a delivery rather than a sale. scope is accepted on /catalog,
/catalog/count, /catalog/facets and /catalog/sources alike, and
scope=private answers 403 for an organisation without the feature.
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.
nulltrue (default) | false. While on, the page is spread across the facets a buyer filters on (funding source, cex/classic kind, tier, persona, timezone profile, funding window), so every value the filters allow is represented instead of the sort column handing the whole page to one of them (sources=kucoin,gate&sort=price coming back all-kucoin). The requested sort still picks which wallet of a group comes first, so the page reads as that sort dealt round-robin across facets. Set false for a strictly monotonic sort column (exports, price ladders); ignored for sort=random, which is the diversified order.
Comma-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.
public (default): the marketplace catalogue. private: the org's own inventory, available to orgs with the private marketplace enabled.
random (default) | age | balance | price | tx_count. random has no sort column at all: the page is the facet rotation over a reproducible shuffle, and order is ignored in that mode.
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": [ { "balance": "string", "chain": "string", "cost_basis": "string", "created_at": "string", "first_tx_at": "string", "funded_at": "string", "funding_exchange": "string", "funding_source": "string", "id": "string", "last_tx_at": "string", "network": "string", "persona_name": "string", "pubkey": "string", "source_kind": "string", "tier": "string", "timezone_name": "string", "token_holdings": [ { "balance": "string", "decimals": 0, "mint": "string", "post_sale": true, "sellable_balance": "string", "sellable_usd_value": 0, "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.
nulltrue (default) | false. While on, the page is spread across the facets a buyer filters on (funding source, cex/classic kind, tier, persona, timezone profile, funding window), so every value the filters allow is represented instead of the sort column handing the whole page to one of them (sources=kucoin,gate&sort=price coming back all-kucoin). The requested sort still picks which wallet of a group comes first, so the page reads as that sort dealt round-robin across facets. Set false for a strictly monotonic sort column (exports, price ladders); ignored for sort=random, which is the diversified order.
Comma-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.
public (default): the marketplace catalogue. private: the org's own inventory, available to orgs with the private marketplace enabled.
random (default) | age | balance | price | tx_count. random has no sort column at all: the page is the facet rotation over a reproducible shuffle, and order is ignored in that mode.
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.
nulltrue (default) | false. While on, the page is spread across the facets a buyer filters on (funding source, cex/classic kind, tier, persona, timezone profile, funding window), so every value the filters allow is represented instead of the sort column handing the whole page to one of them (sources=kucoin,gate&sort=price coming back all-kucoin). The requested sort still picks which wallet of a group comes first, so the page reads as that sort dealt round-robin across facets. Set false for a strictly monotonic sort column (exports, price ladders); ignored for sort=random, which is the diversified order.
Comma-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.
public (default): the marketplace catalogue. private: the org's own inventory, available to orgs with the private marketplace enabled.
random (default) | age | balance | price | tx_count. random has no sort column at all: the page is the facet rotation over a reproducible shuffle, and order is ignored in that mode.
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
public (default) or private (the org's own inventory).
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