Manage sellers

A new rate, trust earned, a seller who leaves. One call each, with your organization key, per mode.

Change their commission

Change a member's fee

members-update.sh

# The organization's fee on a member's payments. A checkout already created keeps its fee.curl -X PATCH "https://api.qbitflow.app/v2/members/$MEMBER_UUID" \  -H "X-API-Key: $QBITFLOW_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "organizationFeePercent": "10"  }'# 200: a Member
// A percent string ('0' to '50'). Applies to their new checkouts: one already created keeps// its fee.const updated = await client.members.update(memberUuid, { organizationFeePercent: '10' });console.log(`fee now ${updated.organizationFeePercent} %`);
# The fee on their new payments, a percent string from "0" to "50" (a checkout already# created keeps its fee).member = client.members.update(member_uuid, organization_fee_percent="10")print(member.organization_fee_percent)
// The organization's commission on their payments, a percent string ("0" to "50"; a// checkout already created keeps its fee).member, err := client.Members.Update(ctx, memberUUID, &qbitflow.UpdateMemberParams{	OrganizationFeePercent: "10",})if err != nil {	log.Fatal(err)}fmt.Println("fee now", member.OrganizationFeePercent, "%")
$member = $client->members->update($memberUuid, new \QBitFlow\Params\UpdateMemberParams(	organizationFeePercent: '10', // a percent string ("0" to "50"); existing checkouts keep their fee));echo "Fee now {$member->organizationFeePercent} %\n";

organizationFeePercent, 0 to 50, in the key's mode only.

  • An open checkout keeps the fee it was created with.
  • A running subscription's next bills take the new one, unless it was created while the fee was 0 % (or paid directly on a chain where you had no wallet): that one never pays a fee.
  • Nothing tells the seller: tell them yourself.

Trust them

Trust a member

members-trust.sh

# Their new payments go to their own wallets. What is already held stays held until you release it# from the dashboard.curl -X POST "https://api.qbitflow.app/v2/members/$MEMBER_UUID/trust" \  -H "X-API-Key: $QBITFLOW_API_KEY"# 200: a Member
// Their new payments go to their own wallets directly (one-way). What is already held stays// held until you release it from the dashboard (heldFunds.released tells you).try {	const trusted = await client.members.trust(memberUuid);	console.log(`trusted since ${trusted.trustedAt}`);} catch (err) {	if (!(err instanceof ConflictError && err.code === 'member_has_no_wallet')) throw err;	console.log('not trusted: their own wallets accept none of your currencies yet');}
# Their new payments go to their own wallets from now on (one-way). What is held stays held# until you release it from the dashboard (heldFunds.released tells you).try:    member = client.members.trust(member_uuid)    print("trusted since", member.trusted_at)except qbitflow.ConflictError as exc:    if exc.code != "member_has_no_wallet":        raise    print("not trusted: their own wallets accept none of your currencies yet")
// Their new payments go to their own wallets from now on (one-way). What is held stays// held until you release it in the dashboard (heldFunds.released tells you).member, err := client.Members.Trust(ctx, memberUUID)var conflict *qbitflow.ConflictErrorswitch {case errors.As(err, &conflict) && conflict.Code == "member_has_no_wallet":	fmt.Println("not trusted: their own wallets accept none of your currencies yet")case err != nil:	log.Fatal(err)case member.TrustedAt != nil:	fmt.Println("trusted since", member.TrustedAt.Format(time.RFC3339))}
// Their new payments go to their own wallets from now on (one-way). What is already held stays// held until you release it from the dashboard (heldFunds.released tells you).try {	$member = $client->members->trust($memberUuid);	echo 'Trusted since ' . ($member->trustedAt?->format(DATE_ATOM) ?? '?') . "\n";} catch (\QBitFlow\Exceptions\ConflictException $e) {	if ($e->apiCode !== 'member_has_no_wallet') {		throw $e;	}	echo "Not trusted: their own wallets accept none of your currencies yet\n";}

Their new sales go straight to their own wallet (they need one). What you hold stays held until you release it. QBitFlow emails them their terms and what you still hold for them. Once trusted, they can sell subscriptions, paid to their wallet.

See their wallets

List a member's wallets

members-wallets.sh

# A member's wallets, where they are paid. A checkout nobody could pay (the space's wallets, the# organization's while it holds the member's funds, accept no currency) answers 409# merchant_not_ready.curl "https://api.qbitflow.app/v2/members/$MEMBER_UUID/wallets" \  -H "X-API-Key: $QBITFLOW_API_KEY"# 200: a page of Wallet ({ items, hasMore: false })
// Where the member is paid. Without a wallet, their checkouts answer 409 merchant_not_ready.const wallets = await client.wallets.listForMember(memberUuid);for (const wallet of wallets) {	console.log(`${wallet.currency.chain}: ${wallet.address}`);}
for wallet in client.wallets.list_for_member(member_uuid):    print(wallet.currency.chain, wallet.address)
wallets, err := client.Wallets.ListForMember(ctx, memberUUID)if err != nil {	log.Fatal(err)}for _, w := range wallets {	fmt.Println(w.Currency.Chain, w.Address)}
foreach ($client->wallets->listForMember($memberUuid) as $wallet) {	echo "{$wallet->currency->chain} {$wallet->address}\n";}

Only the seller adds or removes wallets, from their own dashboard, signing to prove each one is theirs. Your team can't, even acting for them.

Remove a seller

Remove a member

members-remove.sh

# Ends their membership. While the organization holds their funds: 409 held_funds_pending (release# them first).curl -X DELETE "https://api.qbitflow.app/v2/members/$MEMBER_UUID" \  -H "X-API-Key: $QBITFLOW_API_KEY"# 204: no body
// Ends their membership: their keys stop working and their checkouts close.try {	await client.members.remove(memberUuid);	console.log('member removed');} catch (err) {	if (!(err instanceof ConflictError && err.code === 'held_funds_pending')) throw err;	console.log('funds are still held for them: release them first');}
try:    client.members.remove(member_uuid)  # their keys stop working, their checkouts close    print("removed")except qbitflow.ConflictError as exc:    if exc.code != "held_funds_pending":        raise    print("release their held funds first")  # from the dashboard
err := client.Members.Remove(ctx, memberUUID)var conflict *qbitflow.ConflictErrorswitch {case errors.As(err, &conflict) && conflict.Code == "held_funds_pending":	fmt.Println("not removed: release the funds held for them first")case err != nil:	log.Fatal(err)default:	fmt.Println("removed: their keys stop working and their checkouts close")}
try {	$client->members->remove($memberUuid); // their keys stop working, their checkouts close	echo "Removed\n";} catch (\QBitFlow\Exceptions\ConflictException $e) {	if ($e->apiCode !== 'held_funds_pending') {		throw $e;	}	echo "You still hold their funds: release them in the dashboard first\n";}

Their membership in that mode ends at once:

  • their keys and sessions there stop working;
  • their checkouts take no more payments (410 merchant_closed), their products are hidden, their subscriptions are cancelled;
  • their records stay with you, their account stays theirs: a new invitation brings them back.

member.removed reaches your endpoint, the seller as data:

member.removed· the body your endpoint receives

{  "createdAt": "2026-10-01T12:00:00Z",  "data": {    "email": "alice@example.com",    "organizationFeePercent": "5",    "trustedAt": "2026-07-01T09:00:00Z",    "userUuid": "019eca82-5680-7b00-8000-0000000000b1",    … 6 more fields  },  "id": "evt_d32aec3c-d46c-57e3-9292-f8433766df46",  "test": false,  "type": "member.removed",  "version": "v2"}
The contract's example (webhooks.md § Examples)
  1. data.trustedAt: When you started paying them directly, absent while held.
  2. data.userUuid: The seller who left: drop what you keep for them.

Watch out

Release first

A seller you still hold live funds for can't be removed: 409 held_funds_pending. Release first (the previous step). Test-mode funds never block a removal.

Check it

A new fee: the answer's organizationFeePercent changes. Trusted: trustedAt is set. Removed: reading them answers 404, and member.removed arrives.