Balance
What accrues to your organisation, the ledger behind it, and how to take it out.
Your organisation holds a balance per chain. It is a claim against the platform treasury rather than a wallet you have keys to, which is why taking money out is a request rather than a transfer.
Where the balance comes from
Two things credit it, and the bigger one by far is your own margin on sales.
Every settled order credits margin_total, the difference between the
platform's price for the wallets and what you resold them at, on the order's
chain. Nothing to claim and nothing to invoice: it lands as one ledger entry
when the order settles. See
Price breakdown for where that number
comes from.
The other source is funding fees. Half of the platform take on every funding plan your organisation runs is credited back to you, on the plan's chain, once the fee is actually collected.
Withdrawals debit it. So does a refund, which reverses the share of the margin that the refunded amount represents. Everything that moves the balance lands in the ledger.
GET /balance returns both halves in one call: the per-chain totals, and the
ledger entries behind them. Each entry carries a kind, a signed amount, an
optional sale_id, and a ref_key that identifies it uniquely.
kind | Sign | What it is |
|---|---|---|
margin_credit | + | your margin on a settled order |
funding_fee_share | + | your half of the platform fee on a funding plan |
withdrawal | − | money you asked to take out |
refund_debit | − | the pro-rata margin reversed by a refund |
adjustment | ± | a correction, such as a withdrawal whose payout failed |
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/balance"{ "balances": [ { "amount": "string", "chain": "string" } ], "ledger": [ { "amount": "string", "chain": "string", "created_at": "string", "id": 0, "kind": "string", "note": "string", "payout_at": "string", "payout_status": "string", "payout_tx": "string", "ref_key": "string", "sale_id": "string" } ]}Withdrawing
POST /balance/withdraw asks for an amount on a chain to be sent to an address
you name. It is an organisation-admin action, so it needs a user session and an
API key will not do.
What comes back is the ledger entry, not a transaction hash. The debit is recorded immediately and the payout is queued behind it, so the money leaves when the platform processes it.
The entry then tells you how the payout is doing. A withdrawal entry carries
payout_status, which runs pending while the hold lasts, then broadcasting
and awaiting_confirm, then confirmed with the transaction in payout_tx,
and payout_at is the last time it moved. A payout that dies ends failed,
and the balance is re-credited by an adjustment entry, so the money is never
silently lost between the ledger and the chain.
Two things the call refuses outright: an amount of zero or less, with 400, and
an amount above your balance on that chain, with 409 and both figures in the
message.
The address is not inferred and not remembered. Every withdrawal names its own destination, and it is checked against nothing, so get it right.
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.
Response Body
application/json
curl -X POST "https://example.com/balance/withdraw" \ -H "Content-Type: application/json" \ -d '{ "amount": "string", "chain": "string", "to_address": "string" }'{ "amount": "string", "chain": "string", "created_at": "string", "id": 0, "kind": "string", "note": "string", "payout_at": "string", "payout_status": "string", "payout_tx": "string", "ref_key": "string", "sale_id": "string"}Withdrawing without asking
An organisation that wants its margin on its own wallet as soon as it is earned should not have to remember to ask. Register the destinations once, say when they are used, and the platform sends the money on its own.
Your destinations
POST /balance/withdraw-addresses registers an address for a chain, with an
optional label. You can register several per chain; when a withdrawal goes
out, one of the enabled addresses on that chain is picked at random, so the same
wallet does not collect everything.
Addresses are checked at the door, base58 for Solana and 0x for the EVM
chains. A typo here is not a failed request, it is money sent to nobody, over
and over.
PUT /balance/withdraw-addresses/{addr_id} flips one between enabled and
disabled, which is the reversible way to take a destination out of the rotation.
DELETE removes it outright.
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/balance/withdraw-addresses"[ { "address": "string", "chain": "string", "created_at": "string", "enabled": true, "id": "string", "label": "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.
Response Body
application/json
curl -X POST "https://example.com/balance/withdraw-addresses" \ -H "Content-Type: application/json" \ -d '{ "address": "string", "chain": "string" }'{ "address": "string", "chain": "string", "created_at": "string", "enabled": true, "id": "string", "label": "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 PUT "https://example.com/balance/withdraw-addresses/string" \ -H "Content-Type: application/json" \ -d '{ "enabled": true }'{ "ok": true}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/balance/withdraw-addresses/string"{ "ok": true}When they are used
PUT /balance/withdraw-config sets the policy. GET reads it back.
| Field | What it does |
|---|---|
mode | off, per_sale or cron |
cron | the schedule in cron mode, five-field crontab, UTC. Defaults to 0 6 * * * |
min_amount | floor below which nothing goes out, in base units. 0 disables the floor |
delay_secs | how long a transfer is held before it is sent. Defaults to 300 |
next_run_at | read-only, the next occurrence, set only in cron mode |
per_sale sends that order's margin the moment it settles, on the order's
chain. One withdrawal per sale, never two, whatever happens on our side. A
margin under min_amount is not sent and not accumulated either: it stays on
your balance, where the next mode can pick it up.
cron runs on your own schedule and looks at each chain in turn. A chain
whose balance clears min_amount is withdrawn in full, in one entry. A chain
below it is left alone until it clears.
off is the default, and an organisation that configures nothing behaves
exactly as it always did.
Either way the debit lands in the ledger as an ordinary withdrawal entry, so
GET /balance remains the whole story and there is no second place to look.
The hold is there on purpose. A withdrawal fired in the same instant as the settlement that earned it can get ahead of the money it is meant to send. Five minutes is the default for that reason; shorten it only if you know why.
Nothing goes out to an address we were not given. A chain you hold a balance on with no enabled address there is skipped, never guessed at. If the money is not moving, that is the first thing to check.
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/balance/withdraw-config"{ "cron": "string", "delay_secs": 0, "min_amount": "string", "mode": "string", "next_run_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.
Response Body
application/json
curl -X PUT "https://example.com/balance/withdraw-config" \ -H "Content-Type: application/json" \ -d '{ "cron": "string", "delay_secs": 0, "min_amount": "string", "mode": "string" }'{ "cron": "string", "delay_secs": 0, "min_amount": "string", "mode": "string", "next_run_at": "string"}Last updated on