Private marketplace
Fund your own inventory from a deposit, let the platform farm and list it for you alone, and deliver it to your customers at no charge.
The marketplace sells wallets the platform produced. With the private marketplace your organisation produces its own: you draft a funding plan, send the money to a deposit address, and the platform does what it does for its own stock, funds the wallets through exchanges and proxies, farms them under the personas you chose, and lists them when they are ready. They are listed for you only, and you hand them to your customers without paying for them a second time.
The feature is switched on per organisation. GET /config tells you whether
yours has it (private_marketplace) and what the platform charges on each plan
(funding_fee_bps). Without it every route on this page answers 403.
A plan, from draft to inventory
A plan goes through five states, and you drive the first two transitions.
| Status | Meaning |
|---|---|
draft | being configured; the only state a plan can be edited or deleted in |
awaiting_funds | armed: it has a deposit address and a required amount |
launching | money seen, funding jobs being created |
executing | wallets being funded and farmed |
done / failed | every funding job has stopped |
cancelled | dropped from draft or awaiting_funds |
Drafting
POST /inventory/plans creates a draft. The configuration is the operator's
own planner: a solve_mode of budget (fix the money, derive the wallet count)
or spec (fix the counts, derive the cost), a USD budget_usd in budget mode,
the share of wallets routed through exchanges rather than proxies as cex_pct,
and one or more segments.
A segment is one chain's worth of wallets: how many or what share of the budget,
the funding each wallet draws between amount_min and amount_max (base units
of the segment's chain), the gap between funding groups, and the farming it gets
afterwards, as mixes of tiers, personas and timezone profiles. GET /inventory/taxonomy lists the persona and timezone profile ids a mix can name.
POST /inventory/plans/simulate forecasts an unsaved configuration, and GET /inventory/plans/{id}/simulate a saved one: how many wallets, what they cost in
USD, how long funding takes, and the checks the planner ran. Use it while
editing; nothing is committed.
Authorization
bearerAuth JWT from /auth/login (users) or an org API key (mk_...) for integrations.
In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
An org's own plan: the planner config without a source wallet (the org pays through the deposit minted when the plan is armed).
Response Body
application/json
curl -X POST "https://example.com/inventory/plans" \ -H "Content-Type: application/json" \ -d '{ "name": "string" }'{ "armed_at": "string", "budget_source": "string", "budget_usd": 0, "cex_pct": 0, "completed_at": "string", "created_at": "string", "created_by": "string", "deposit_address": "string", "deposit_balance": "string", "deposit_chain": "string", "fee_amount": "string", "fee_bps": 0, "fee_swept_at": "string", "id": "string", "job_ids": [ "string" ], "launch_balance": "string", "name": "string", "notes": "string", "org_id": "string", "required_amount": "string", "segments": [ { "amount_max": "string", "amount_min": "string", "chain": "string", "farm_duration_days": null, "gap_max_mins": 0, "gap_min_mins": 0, "group_size": 1, "list_at_age_hours": null, "list_at_tx_count": null, "list_combinator": null, "min_tx": 0, "persona_mix": {}, "providers": [], "share_pct": 0, "target_age_days": null, "target_count": 0, "tier_mix": {}, "timezone_mix": {}, "tx_per_day_max": null, "tx_per_day_min": null } ], "solve_mode": "string", "source_wallet_id": "string", "status": "string", "updated_at": "string", "validated_at": "string"}Authorization
bearerAuth JWT from /auth/login (users) or an org API key (mk_...) for integrations.
In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
An org's own plan: the planner config without a source wallet (the org pays through the deposit minted when the plan is armed).
Response Body
application/json
curl -X POST "https://example.com/inventory/plans/simulate" \ -H "Content-Type: application/json" \ -d '{ "name": "string" }'{ "active_wallets": 0, "avg_tx": 0.1, "budget_usd": 0.1, "cex_wallets": 0, "classic_wallets": 0, "curve": [ { "expected": 0, "hi": 0, "lo": 0, "t_mins": 0.1 } ], "finish_mins_expected": 0.1, "finish_mins_max": 0.1, "finish_mins_min": 0.1, "over_budget": true, "remaining_usd": 0.1, "segments": [ { "active_wallets": 0, "amount_max_native": 0.1, "amount_min_native": 0.1, "avg_tx": 0.1, "below_cex_min": true, "cex_min_native": 0, "cex_min_usd": 0, "chain": "string", "cost_usd": 0.1, "duration_mins_expected": 0.1, "duration_mins_max": 0.1, "duration_mins_min": 0.1, "groups": 0, "mature_at_days": 0, "price_usd": 0.1, "wallets": 0 } ], "total_cost_usd": 0.1, "total_wallets": 0, "wallets_per_day": 0.1, "warnings": [ "string" ]}Authorization
bearerAuth JWT from /auth/login (users) or an org API key (mk_...) for integrations.
In: header
Response Body
application/json
curl -X GET "https://example.com/inventory/taxonomy"{ "personas": [ { "id": "string", "name": "string" } ], "timezones": [ { "id": "string", "name": "string" } ]}Authorization
bearerAuth JWT from /auth/login (users) or an org API key (mk_...) for integrations.
In: header
Path Parameters
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
An org's own plan: the planner config without a source wallet (the org pays through the deposit minted when the plan is armed).
Response Body
application/json
curl -X PUT "https://example.com/inventory/plans/string" \ -H "Content-Type: application/json" \ -d '{ "name": "string" }'{ "armed_at": "string", "budget_source": "string", "budget_usd": 0, "cex_pct": 0, "completed_at": "string", "created_at": "string", "created_by": "string", "deposit_address": "string", "deposit_balance": "string", "deposit_chain": "string", "fee_amount": "string", "fee_bps": 0, "fee_swept_at": "string", "id": "string", "job_ids": [ "string" ], "launch_balance": "string", "name": "string", "notes": "string", "org_id": "string", "required_amount": "string", "segments": [ { "amount_max": "string", "amount_min": "string", "chain": "string", "farm_duration_days": null, "gap_max_mins": 0, "gap_min_mins": 0, "group_size": 1, "list_at_age_hours": null, "list_at_tx_count": null, "list_combinator": null, "min_tx": 0, "persona_mix": {}, "providers": [], "share_pct": 0, "target_age_days": null, "target_count": 0, "tier_mix": {}, "timezone_mix": {}, "tx_per_day_max": null, "tx_per_day_min": null } ], "solve_mode": "string", "source_wallet_id": "string", "status": "string", "updated_at": "string", "validated_at": "string"}Arming: getting a deposit address
POST /inventory/plans/{id}/arm freezes the draft and mints its deposit. You
choose the chain you will deposit on; segments on another chain are funded
cross-asset through the exchanges. The response carries deposit_address,
deposit_chain and required_amount, and the plan is now awaiting_funds.
required_amount is sized so the plan can fund every wallet even if each draws
its maximum: the worst case, grossed up for the exchanges' pre-flight margin,
plus the platform fee and the deposit's own transaction costs. What the plan
does not spend stays on the deposit and comes back to you at the end.
The fee rate is frozen on the plan at this point (fee_bps), so a plan you are
already sending money to is never repriced.
Authorization
bearerAuth JWT from /auth/login (users) or an org API key (mk_...) for integrations.
In: header
Path Parameters
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
curl -X POST "https://example.com/inventory/plans/string/arm" \ -H "Content-Type: application/json" \ -d '{ "deposit_chain": "string" }'{ "armed_at": "string", "budget_source": "string", "budget_usd": 0, "cex_pct": 0, "completed_at": "string", "created_at": "string", "created_by": "string", "deposit_address": "string", "deposit_balance": "string", "deposit_chain": "string", "fee_amount": "string", "fee_bps": 0, "fee_swept_at": "string", "id": "string", "job_ids": [ "string" ], "launch_balance": "string", "name": "string", "notes": "string", "org_id": "string", "required_amount": "string", "segments": [ { "amount_max": "string", "amount_min": "string", "chain": "string", "farm_duration_days": null, "gap_max_mins": 0, "gap_min_mins": 0, "group_size": 1, "list_at_age_hours": null, "list_at_tx_count": null, "list_combinator": null, "min_tx": 0, "persona_mix": {}, "providers": [], "share_pct": 0, "target_age_days": null, "target_count": 0, "tier_mix": {}, "timezone_mix": {}, "tx_per_day_max": null, "tx_per_day_min": null } ], "solve_mode": "string", "source_wallet_id": "string", "status": "string", "updated_at": "string", "validated_at": "string"}Launching
Send the money. The platform watches the deposit and launches the plan on its
own once the balance covers required_amount; nothing more to call.
POST /inventory/plans/{id}/launch launches it earlier, with whatever has
arrived. The budget is then what the deposit holds, net of the fee and of the
deposit's transaction costs, so fewer wallets are funded than the plan asked
for. A deposit too small to fund a single wallet is refused and the plan stays
awaiting_funds.
Launching is what takes the platform fee: fee_amount, at fee_bps of the
deposit, is swept to the platform once the funding jobs exist, and never before.
launch_balance records what the launch was sized on.
Authorization
bearerAuth JWT from /auth/login (users) or an org API key (mk_...) for integrations.
In: header
Path Parameters
Response Body
application/json
curl -X POST "https://example.com/inventory/plans/string/launch"{ "cex_wallets": 0, "classic_wallets": 0, "job_ids": [ "string" ], "plan_id": "string"}Watching it run
GET /inventory/plans/{id} is the plan itself, with the deposit's balance as
last read on chain (deposit_balance) and the ids of the funding jobs it
launched. GET /inventory/plans lists them all.
The wallets appear in GET /inventory/wallets as soon as they are created,
and move through the same statuses as platform stock: created while waiting
for funding, funded while farming, listed once they reach your private
catalog, reserved and sold as you deliver them. GET /inventory/summary
gives the counts by status with the plan list in one call.
Authorization
bearerAuth JWT from /auth/login (users) or an org API key (mk_...) for integrations.
In: header
Response Body
application/json
curl -X GET "https://example.com/inventory/plans"[ { "armed_at": "string", "budget_source": "string", "budget_usd": 0, "cex_pct": 0, "completed_at": "string", "created_at": "string", "created_by": "string", "deposit_address": "string", "deposit_balance": "string", "deposit_chain": "string", "fee_amount": "string", "fee_bps": 0, "fee_swept_at": "string", "id": "string", "job_ids": [ "string" ], "launch_balance": "string", "name": "string", "notes": "string", "org_id": "string", "required_amount": "string", "segments": [ { "amount_max": "string", "amount_min": "string", "chain": "string", "farm_duration_days": null, "gap_max_mins": 0, "gap_min_mins": 0, "group_size": 1, "list_at_age_hours": null, "list_at_tx_count": null, "list_combinator": null, "min_tx": 0, "persona_mix": {}, "providers": [], "share_pct": 0, "target_age_days": null, "target_count": 0, "tier_mix": {}, "timezone_mix": {}, "tx_per_day_max": null, "tx_per_day_min": null } ], "solve_mode": "string", "source_wallet_id": "string", "status": "string", "updated_at": "string", "validated_at": "string" }]Authorization
bearerAuth JWT from /auth/login (users) or an org API key (mk_...) for integrations.
In: header
Path Parameters
Response Body
application/json
curl -X GET "https://example.com/inventory/plans/string"{ "armed_at": "string", "budget_source": "string", "budget_usd": 0, "cex_pct": 0, "completed_at": "string", "created_at": "string", "created_by": "string", "deposit_address": "string", "deposit_balance": "string", "deposit_chain": "string", "fee_amount": "string", "fee_bps": 0, "fee_swept_at": "string", "id": "string", "job_ids": [ "string" ], "launch_balance": "string", "name": "string", "notes": "string", "org_id": "string", "required_amount": "string", "segments": [ { "amount_max": "string", "amount_min": "string", "chain": "string", "farm_duration_days": null, "gap_max_mins": 0, "gap_min_mins": 0, "group_size": 1, "list_at_age_hours": null, "list_at_tx_count": null, "list_combinator": null, "min_tx": 0, "persona_mix": {}, "providers": [], "share_pct": 0, "target_age_days": null, "target_count": 0, "tier_mix": {}, "timezone_mix": {}, "tx_per_day_max": null, "tx_per_day_min": null } ], "solve_mode": "string", "source_wallet_id": "string", "status": "string", "updated_at": "string", "validated_at": "string"}Authorization
bearerAuth JWT from /auth/login (users) or an org API key (mk_...) for integrations.
In: header
Query Parameters
nullint6450Response Body
application/json
curl -X GET "https://example.com/inventory/wallets"{ "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, "inventory_org_id": "string", "key_purged_at": "string", "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", "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"}Authorization
bearerAuth JWT from /auth/login (users) or an org API key (mk_...) for integrations.
In: header
Response Body
application/json
curl -X GET "https://example.com/inventory/summary"{ "counts": [ { "count": 0, "status": "string" } ], "plans": [ { "armed_at": "string", "budget_source": "string", "budget_usd": 0, "cex_pct": 0, "completed_at": "string", "created_at": "string", "created_by": "string", "deposit_address": "string", "deposit_balance": "string", "deposit_chain": "string", "fee_amount": "string", "fee_bps": 0, "fee_swept_at": "string", "id": "string", "job_ids": [ "string" ], "launch_balance": "string", "name": "string", "notes": "string", "org_id": "string", "required_amount": "string", "segments": [ { "amount_max": "string", "amount_min": "string", "chain": "string", "farm_duration_days": null, "gap_max_mins": 0, "gap_min_mins": 0, "group_size": 1, "list_at_age_hours": null, "list_at_tx_count": null, "list_combinator": null, "min_tx": 0, "persona_mix": {}, "providers": [], "share_pct": 0, "target_age_days": null, "target_count": 0, "tier_mix": {}, "timezone_mix": {}, "tx_per_day_max": null, "tx_per_day_min": null } ], "solve_mode": "string", "source_wallet_id": "string", "status": "string", "updated_at": "string", "validated_at": "string" } ]}Backing out, and getting the rest back
POST /inventory/plans/{id}/cancel drops a draft or an armed plan. Once
launched there is nothing to cancel: the money is on its way to the wallets.
POST /inventory/plans/{id}/withdraw-leftover sends whatever is still on the
deposit to one of your registered
withdrawal addresses on that chain. It
is available once the plan is done, failed or cancelled, and refused while
any transfer from the deposit is still in flight. The destination has to be an
address you registered, enabled, on the deposit's chain: the money is yours, and
it only ever goes somewhere you named in advance.
Authorization
bearerAuth JWT from /auth/login (users) or an org API key (mk_...) for integrations.
In: header
Path Parameters
Response Body
application/json
curl -X POST "https://example.com/inventory/plans/string/cancel"{ "armed_at": "string", "budget_source": "string", "budget_usd": 0, "cex_pct": 0, "completed_at": "string", "created_at": "string", "created_by": "string", "deposit_address": "string", "deposit_balance": "string", "deposit_chain": "string", "fee_amount": "string", "fee_bps": 0, "fee_swept_at": "string", "id": "string", "job_ids": [ "string" ], "launch_balance": "string", "name": "string", "notes": "string", "org_id": "string", "required_amount": "string", "segments": [ { "amount_max": "string", "amount_min": "string", "chain": "string", "farm_duration_days": null, "gap_max_mins": 0, "gap_min_mins": 0, "group_size": 1, "list_at_age_hours": null, "list_at_tx_count": null, "list_combinator": null, "min_tx": 0, "persona_mix": {}, "providers": [], "share_pct": 0, "target_age_days": null, "target_count": 0, "tier_mix": {}, "timezone_mix": {}, "tx_per_day_max": null, "tx_per_day_min": null } ], "solve_mode": "string", "source_wallet_id": "string", "status": "string", "updated_at": "string", "validated_at": "string"}Authorization
bearerAuth JWT from /auth/login (users) or an org API key (mk_...) for integrations.
In: header
Path Parameters
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
curl -X POST "https://example.com/inventory/plans/string/withdraw-leftover" \ -H "Content-Type: application/json" \ -d '{ "address_id": "string" }'{ "attempts": 0, "chain": "string", "created_at": "string", "id": "string", "kind": "string", "last_error": "string", "next_run_at": "string", "payload": null, "status": "string", "tx_hash": "string", "updated_at": "string", "wallet_id": "string"}Authorization
bearerAuth JWT from /auth/login (users) or an org API key (mk_...) for integrations.
In: header
Path Parameters
Response Body
application/json
curl -X DELETE "https://example.com/inventory/plans/string"{ "ok": true}Selling what you produced
Your listed wallets show up in the catalog
under scope=private, and a quote
with "scope": "private" delivers them. There is no price: a private quote
with no top-up settles the moment it is created, and the keys are available
through the usual routes. With a top-up, the customer pays for the top-up alone.
Deliveries are not sales. They credit no margin to your balance and count in
none of the sales statistics, since no money changed hands. They do show in your
purchases and on the wallets as sold_at and buyer_ref, so the customer
history reads the same whether a wallet came from the marketplace or from your
own stock.
Who may do what
Creating, editing, arming, launching, cancelling a plan and withdrawing the leftover need an organisation admin signed in as a user; an API key reads plans and inventory, and delivers wallets, but does not move money. See Authentication.
Last updated on